Module: wine Branch: master Commit: da2522becb3c167ddba5457ee460a7194eb505e9 URL: http://source.winehq.org/git/wine.git/?a=commit;h=da2522becb3c167ddba5457ee4...
Author: Alexandre Julliard julliard@winehq.org Date: Tue May 30 14:19:57 2017 +0200
wineandroid: Install libraries from the package assets if present.
Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/wineandroid.drv/Makefile.in | 5 + dlls/wineandroid.drv/WineActivity.java | 164 +++++++++++++++++++++++++++++++++ 2 files changed, 169 insertions(+)
diff --git a/dlls/wineandroid.drv/Makefile.in b/dlls/wineandroid.drv/Makefile.in index 42c6926..0001dec 100644 --- a/dlls/wineandroid.drv/Makefile.in +++ b/dlls/wineandroid.drv/Makefile.in @@ -8,4 +8,9 @@ EXTRA_TARGETS = wine-debug.apk all: wine-debug.apk
wine-debug.apk: build.gradle $(srcdir)/AndroidManifest.xml $(srcdir)/WineActivity.java $(srcdir)/wine.svg + (test -d assets && \ + rm -f assets/files.sum assets/sums.sum && \ + sha256sum `find assets -type f -print` | sed 's/ assets// /' >files.sum && \ + sha256sum files.sum >sums.sum && \ + mv files.sum sums.sum assets) || rm -rf assets gradle -q assembleDebug && mv build/outputs/apk/wine-debug.apk . diff --git a/dlls/wineandroid.drv/WineActivity.java b/dlls/wineandroid.drv/WineActivity.java index ceac1b6..84ce463 100644 --- a/dlls/wineandroid.drv/WineActivity.java +++ b/dlls/wineandroid.drv/WineActivity.java @@ -21,13 +21,177 @@ package org.winehq.wine;
import android.app.Activity; +import android.app.ProgressDialog; +import android.content.SharedPreferences; +import android.os.Build; import android.os.Bundle; +import android.preference.PreferenceManager; +import android.util.Log; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map;
public class WineActivity extends Activity { + private final String LOGTAG = "wine"; + private ProgressDialog progress_dialog; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate( savedInstanceState ); + + requestWindowFeature( android.view.Window.FEATURE_NO_TITLE ); + + new Thread( new Runnable() { public void run() { loadWine(); }} ).start(); + } + + private void loadWine() + { + copyAssetFiles(); + runOnUiThread( new Runnable() { public void run() { progress_dialog.dismiss(); }}); + } + + private void createProgressDialog( final int max, final String message ) + { + runOnUiThread( new Runnable() { public void run() { + if (progress_dialog != null) progress_dialog.dismiss(); + progress_dialog = new ProgressDialog( WineActivity.this ); + progress_dialog.setProgressStyle( max > 0 ? ProgressDialog.STYLE_HORIZONTAL + : ProgressDialog.STYLE_SPINNER ); + progress_dialog.setTitle( "Wine" ); + progress_dialog.setMessage( message ); + progress_dialog.setCancelable( false ); + progress_dialog.setMax( max ); + progress_dialog.show(); + }}); + + } + + private final boolean isFileWanted( String name ) + { + if (name.equals( "files.sum" )) return true; + if (name.startsWith( "share/" )) return true; + if (name.startsWith( Build.CPU_ABI + "/system/" )) return false; + if (name.startsWith( Build.CPU_ABI + "/" )) return true; + if (name.startsWith( "x86/" )) return true; + return false; + } + + private final boolean isFileExecutable( String name ) + { + return name.startsWith( Build.CPU_ABI + "/" ) || name.startsWith( "x86/" ); + } + + private final HashMap<String,String> readMapFromInputStream( InputStream in ) + { + HashMap<String,String> map = new HashMap<String,String>(); + String str; + + try + { + BufferedReader reader = new BufferedReader( new InputStreamReader( in, "UTF-8" )); + while ((str = reader.readLine()) != null) + { + String entry[] = str.split( "\s+", 2 ); + if (entry.length == 2 && isFileWanted( entry[1] )) map.put( entry[1], entry[0] ); + } + } + catch( IOException e ) { } + return map; + } + + private final HashMap<String,String> readMapFromDiskFile( String file ) + { + try + { + return readMapFromInputStream( new FileInputStream( new File( getFilesDir(), file ))); + } + catch( IOException e ) { return new HashMap<String,String>(); } + } + + private final HashMap<String,String> readMapFromAssetFile( String file ) + { + try + { + return readMapFromInputStream( getAssets().open( file ) ); + } + catch( IOException e ) { return new HashMap<String,String>(); } + } + + private final void copyAssetFile( String src ) + { + File dest = new File( getFilesDir(), src ); + try + { + Log.i( LOGTAG, "extracting " + dest ); + dest.getParentFile().mkdirs(); + dest.delete(); + if (dest.createNewFile()) + { + InputStream in = getAssets().open( src ); + FileOutputStream out = new FileOutputStream( dest ); + int read; + byte[] buffer = new byte[65536]; + + while ((read = in.read( buffer )) > 0) out.write( buffer, 0, read ); + out.close(); + if (isFileExecutable( src )) dest.setExecutable( true, true ); + } + else + Log.i( LOGTAG, "Failed to create file " + dest ); + } + catch( IOException e ) + { + Log.i( LOGTAG, "Failed to copy asset file to " + dest ); + dest.delete(); + } + } + + private final void deleteAssetFile( String src ) + { + File dest = new File( getFilesDir(), src ); + Log.i( LOGTAG, "deleting " + dest ); + dest.delete(); + } + + private final void copyAssetFiles() + { + String new_sum = readMapFromAssetFile( "sums.sum" ).get( "files.sum" ); + if (new_sum == null) return; // no assets + + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences( this ); + String old_sum = prefs.getString( "files.sum", "" ); + if (old_sum.equals( new_sum )) return; // no change + prefs.edit().putString( "files.sum", new_sum ).apply(); + + HashMap<String,String> existing_files = readMapFromDiskFile( "files.sum" ); + HashMap<String,String> new_files = readMapFromAssetFile( "files.sum" ); + ArrayList<String> copy_files = new ArrayList<String>(); + copy_files.add( "files.sum" ); + + for (Map.Entry<String, String> entry : new_files.entrySet()) + { + String name = entry.getKey(); + if (!entry.getValue().equals( existing_files.remove( name ))) copy_files.add( name ); + } + + createProgressDialog( copy_files.size(), "Extracting files..." ); + + for (String name : existing_files.keySet()) deleteAssetFile( name ); + + for (String name : copy_files) + { + copyAssetFile( name ); + runOnUiThread( new Runnable() { public void run() { + progress_dialog.incrementProgressBy( 1 ); }}); + } } }