Skip to content

Commit

Permalink
Merge pull request libgdx#3408 from sarkanyi/master
Browse files Browse the repository at this point in the history
Add APK expansion support
  • Loading branch information
Tom-Ski committed Oct 7, 2015
2 parents c4e261a + 4996db6 commit 3177a37
Show file tree
Hide file tree
Showing 11 changed files with 960 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.badlogic.gdx.backends.android;

import java.io.File;
import java.io.IOException;
import java.util.Vector;

import android.content.Context;
import android.os.Environment;

public class APKExpansionSupport {
// The shared path to all app expansion files
private final static String EXP_PATH = "/Android/obb/";

static String[] getAPKExpansionFiles(Context ctx, int mainVersion,
int patchVersion) {
String packageName = ctx.getPackageName();
Vector<String> ret = new Vector<String>();
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
// Build the full path to the app's expansion files
File root = Environment.getExternalStorageDirectory();
File expPath = new File(root.toString() + EXP_PATH + packageName);

// Check that expansion file path exists
if (expPath.exists()) {
if (mainVersion > 0) {
String strMainPath = expPath + File.separator + "main."
+ mainVersion + "." + packageName + ".obb";
File main = new File(strMainPath);
if (main.isFile()) {
ret.add(strMainPath);
}
}
if (patchVersion > 0) {
String strPatchPath = expPath + File.separator + "patch."
+ mainVersion + "." + packageName + ".obb";
File main = new File(strPatchPath);
if (main.isFile()) {
ret.add(strPatchPath);
}
}
}
}
String[] retArray = new String[ret.size()];
ret.toArray(retArray);
return retArray;
}

static public ZipResourceFile getResourceZipFile(String[] expansionFiles)
throws IOException {
ZipResourceFile apkExpansionFile = null;
for (String expansionFilePath : expansionFiles) {
if (null == apkExpansionFile) {
apkExpansionFile = new ZipResourceFile(expansionFilePath);
} else {
apkExpansionFile.addPatchFile(expansionFilePath);
}
}
return apkExpansionFile;
}

static public ZipResourceFile getAPKExpansionZipFile(Context ctx,
int mainVersion, int patchVersion) throws IOException {
String[] expansionFiles = getAPKExpansionFiles(ctx, mainVersion,
patchVersion);
return getResourceZipFile(expansionFiles);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public Music newMusic (FileHandle file) {

if (aHandle.type() == FileType.Internal) {
try {
AssetFileDescriptor descriptor = aHandle.assets.openFd(aHandle.path());
AssetFileDescriptor descriptor = aHandle.getAssetFileDescriptor(aHandle.path());
mediaPlayer.setDataSource(descriptor.getFileDescriptor(), descriptor.getStartOffset(), descriptor.getLength());
descriptor.close();
mediaPlayer.prepare();
Expand Down Expand Up @@ -144,7 +144,7 @@ public Sound newSound (FileHandle file) {
AndroidFileHandle aHandle = (AndroidFileHandle)file;
if (aHandle.type() == FileType.Internal) {
try {
AssetFileDescriptor descriptor = aHandle.assets.openFd(aHandle.path());
AssetFileDescriptor descriptor = aHandle.getAssetFileDescriptor(aHandle.path());
AndroidSound sound = new AndroidSound(soundPool, manager, soundPool.load(descriptor, 1));
descriptor.close();
return sound;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
* @author Nathan Sweet */
public class AndroidFileHandle extends FileHandle {
// The asset manager, or null if this is not an internal file.
final AssetManager assets;
final private AssetManager assets;

AndroidFileHandle (AssetManager assets, String fileName, FileType type) {
super(fileName.replace('\\', '/'), type);
Expand Down Expand Up @@ -229,4 +229,7 @@ public File file () {
return super.file();
}

public AssetFileDescriptor getAssetFileDescriptor(String path) throws IOException {
return assets.openFd(path);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,15 @@

package com.badlogic.gdx.backends.android;

import java.io.IOException;

import android.content.res.AssetManager;
import android.os.Environment;

import com.badlogic.gdx.Files;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.utils.GdxRuntimeException;

/** @author mzechner
* @author Nathan Sweet */
Expand All @@ -29,6 +33,7 @@ public class AndroidFiles implements Files {
protected final String localpath;

protected final AssetManager assets;
private ZipResourceFile expansionFile = null;

public AndroidFiles (AssetManager assets) {
this.assets = assets;
Expand All @@ -42,7 +47,14 @@ public AndroidFiles (AssetManager assets, String localpath) {

@Override
public FileHandle getFileHandle (String path, FileType type) {
return new AndroidFileHandle(type == FileType.Internal ? assets : null, path, type);
FileHandle handle = new AndroidFileHandle(type == FileType.Internal ? assets : null, path, type);
if (!handle.exists() && expansionFile != null) {
// try APK expansion instead
FileHandle zipHandle = new AndroidZipFileHandle(path);
if (zipHandle.exists())
handle = zipHandle;
}
return handle;
}

@Override
Expand All @@ -52,7 +64,14 @@ public FileHandle classpath (String path) {

@Override
public FileHandle internal (String path) {
return new AndroidFileHandle(assets, path, FileType.Internal);
FileHandle handle = new AndroidFileHandle(assets, path, FileType.Internal);
if (!handle.exists() && expansionFile != null) {
// try APK expansion instead
FileHandle zipHandle = new AndroidZipFileHandle(path);
if (zipHandle.exists())
handle = zipHandle;
}
return handle;
}

@Override
Expand Down Expand Up @@ -89,4 +108,31 @@ public String getLocalStoragePath () {
public boolean isLocalStorageAvailable () {
return true;
}

/**
* This method can be called to set the version code of the APK expansion
* file(s) used by the application
*
* @param mainVersion
* - version code of the main expansion file
* @param patchVersion
* - version code of the patch expansion file
*
* @return true if the APK expansion file could be opened, false otherwise
*/
public boolean setAPKExpansion(int mainVersion, int patchVersion) {
try {
expansionFile = APKExpansionSupport.getAPKExpansionZipFile(
((AndroidApplication) Gdx.app).getBaseContext(),
mainVersion, patchVersion);
} catch (IOException ex) {
throw new GdxRuntimeException("APK expansion main version " + mainVersion + " or patch version " + patchVersion + " couldn't be opened!");
}
return expansionFile != null;
}

/** @return The application's APK extension file */
public ZipResourceFile getExpansionFile() {
return expansionFile;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
/*******************************************************************************
* Copyright 2011 See AUTHORS file.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/

package com.badlogic.gdx.backends.android;

import java.io.*;

import android.content.res.AssetFileDescriptor;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Files.FileType;
import com.badlogic.gdx.backends.android.ZipResourceFile.ZipEntryRO;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.utils.GdxRuntimeException;

/** @author sarkanyi */
public class AndroidZipFileHandle extends AndroidFileHandle {
private AssetFileDescriptor assetFd;
private ZipResourceFile expansionFile;
private String path;

public AndroidZipFileHandle(String fileName) {
super(null, fileName, FileType.Internal);
initialize();
}

public AndroidZipFileHandle(File file, FileType type) {
super(null, file, type);
initialize();
}

private void initialize() {
path = file.getPath().replace('\\', '/');
expansionFile = ((AndroidFiles) Gdx.files).getExpansionFile();
assetFd = expansionFile.getAssetFileDescriptor(getPath());

// needed for listing entries and exists() of directories
if (isDirectory())
path += "/";
}

public AssetFileDescriptor getAssetFileDescriptor(String path) throws IOException {
return assetFd;
}

private String getPath() {
return path;
}

@Override
public InputStream read() {
InputStream input = null;

try {
input = expansionFile.getInputStream(getPath());
} catch (IOException ex) {
throw new GdxRuntimeException("Error reading file: " + file + " (ZipResourceFile)", ex);
}
return input;
}

@Override
public FileHandle child(String name) {
if (file.getPath().length() == 0)
return new AndroidZipFileHandle(new File(name), type);
return new AndroidZipFileHandle(new File(file, name), type);
}

@Override
public FileHandle sibling(String name) {
if (file.getPath().length() == 0)
throw new GdxRuntimeException("Cannot get the sibling of the root.");
return new AndroidZipFileHandle(new File(file.getParent(), name), type);
}

@Override
public FileHandle parent() {
File parent = file.getParentFile();
if (parent == null)
parent = new File("");
return new AndroidZipFileHandle(parent.getPath());
}

@Override
public FileHandle[] list() {
ZipEntryRO[] zipEntries = expansionFile.getEntriesAt(getPath());
FileHandle[] handles = new FileHandle[zipEntries.length];
for (int i = 0, n = handles.length; i < n; i++)
handles[i] = new AndroidZipFileHandle(zipEntries[i].mFileName);
return handles;
}

@Override
public FileHandle[] list(FileFilter filter) {
ZipEntryRO[] zipEntries = expansionFile.getEntriesAt(getPath());
FileHandle[] handles = new FileHandle[zipEntries.length];
int count = 0;
for (int i = 0, n = handles.length; i < n; i++) {
FileHandle child = new AndroidZipFileHandle(zipEntries[i].mFileName);
if (!filter.accept(child.file()))
continue;
handles[count] = child;
count++;
}
if (count < zipEntries.length) {
FileHandle[] newHandles = new FileHandle[count];
System.arraycopy(handles, 0, newHandles, 0, count);
handles = newHandles;
}
return handles;
}

@Override
public FileHandle[] list(FilenameFilter filter) {
ZipEntryRO[] zipEntries = expansionFile.getEntriesAt(getPath());
FileHandle[] handles = new FileHandle[zipEntries.length];
int count = 0;
for (int i = 0, n = handles.length; i < n; i++) {
String path = zipEntries[i].mFileName;
if (!filter.accept(file, path))
continue;
handles[count] = new AndroidZipFileHandle(path);
count++;
}
if (count < zipEntries.length) {
FileHandle[] newHandles = new FileHandle[count];
System.arraycopy(handles, 0, newHandles, 0, count);
handles = newHandles;
}
return handles;
}

@Override
public FileHandle[] list(String suffix) {
ZipEntryRO[] zipEntries = expansionFile.getEntriesAt(getPath());
FileHandle[] handles = new FileHandle[zipEntries.length];
int count = 0;
for (int i = 0, n = handles.length; i < n; i++) {
String path = zipEntries[i].mFileName;
if (!path.endsWith(suffix))
continue;
handles[count] = new AndroidZipFileHandle(path);
count++;
}
if (count < zipEntries.length) {
FileHandle[] newHandles = new FileHandle[count];
System.arraycopy(handles, 0, newHandles, 0, count);
handles = newHandles;
}
return handles;
}

@Override
public boolean isDirectory() {
return assetFd == null;
}

@Override
public long length() {
try {
return getAssetFileDescriptor("").getLength();
} catch (IOException e) {
}
return 0;
}

@Override
public boolean exists() {
return expansionFile.getEntriesAt(getPath()).length != 0;
}
}
Loading

0 comments on commit 3177a37

Please sign in to comment.