├── .gitignore ├── .gitmodules ├── .idea ├── gradle.xml └── runConfigurations.xml ├── COPYING ├── README.txt ├── app ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ └── fonts │ │ └── default-1.1.7.ttf │ ├── java │ ├── com │ │ └── onscripter │ │ │ └── plus │ │ │ ├── ActivityPlus.java │ │ │ ├── App.java │ │ │ ├── ChangeLog.java │ │ │ ├── CopyFilesDialogTask.java │ │ │ ├── DataDownloader.java │ │ │ ├── Environment2.java │ │ │ ├── ExtSDCardFix.java │ │ │ ├── FileSystemAdapter.java │ │ │ ├── FolderBrowserDialogPreference.java │ │ │ ├── FolderBrowserDialogWrapper.java │ │ │ ├── GameUtils.java │ │ │ ├── ImageButton2.java │ │ │ ├── LauncherActivity.java │ │ │ ├── ListPreferencePlus.java │ │ │ ├── ONScripter.java │ │ │ ├── ONScripterGame.java │ │ │ ├── ProgressDialogAsyncTask.java │ │ │ ├── Settings.java │ │ │ ├── TwoStateLayout.java │ │ │ ├── UnicodeUtil.java │ │ │ ├── VNPreferences.java │ │ │ ├── VNSettingsDialog.java │ │ │ ├── ViewAdapterBase.java │ │ │ ├── bugtracking │ │ │ ├── BugTrackingService.java │ │ │ ├── ModifyServerRequest.java │ │ │ ├── ONScripterTracer.java │ │ │ └── TracedONScripterView.java │ │ │ └── settings │ │ │ ├── AboutSettingsFragment.java │ │ │ ├── GeneralSettingsFragment.java │ │ │ └── LayoutPreference.java │ └── jrummy │ │ └── sdfix │ │ ├── Remounter.java │ │ ├── SDFix.java │ │ └── Shell.java │ ├── libs │ └── android-support-v4.jar │ └── res │ ├── drawable-hdpi │ ├── ic_action_new.png │ ├── ic_action_new_dark.png │ ├── ic_action_phone.png │ ├── ic_action_phone_dark.png │ ├── ic_action_sd_storage.png │ ├── ic_action_sd_storage_dark.png │ └── icon.png │ ├── drawable-ldpi │ └── icon.png │ ├── drawable-mdpi │ ├── ic_action_new.png │ ├── ic_action_new_dark.png │ ├── ic_action_phone.png │ ├── ic_action_phone_dark.png │ ├── ic_action_sd_storage.png │ ├── ic_action_sd_storage_dark.png │ └── icon.png │ ├── drawable-xhdpi │ ├── ic_action_new.png │ ├── ic_action_new_dark.png │ ├── ic_action_phone.png │ ├── ic_action_phone_dark.png │ ├── ic_action_sd_storage.png │ ├── ic_action_sd_storage_dark.png │ └── icon.png │ ├── drawable-xxhdpi │ ├── ic_action_new.png │ ├── ic_action_new_dark.png │ ├── ic_action_phone.png │ ├── ic_action_phone_dark.png │ ├── ic_action_sd_storage.png │ ├── ic_action_sd_storage_dark.png │ └── icon.png │ ├── drawable-xxxhdpi │ └── icon.png │ ├── drawable │ ├── dark_divider.xml │ ├── ic_action_save.png │ ├── ic_file_dark.png │ ├── ic_file_light.png │ ├── ic_folder_dark.png │ ├── ic_folder_light.png │ ├── ic_folder_up_dark.png │ ├── ic_folder_up_light.png │ ├── ic_menu_change_folder.png │ ├── light_divider.xml │ ├── menu_auto.png │ ├── menu_auto_selected.png │ ├── menu_back.png │ ├── menu_change_speed.png │ ├── menu_change_speed_selected.png │ ├── menu_mouse_right_click.png │ ├── menu_mouse_scroll_down.png │ ├── menu_mouse_scroll_up.png │ ├── menu_settings.png │ ├── menu_skip.png │ └── menu_skip_selected.png │ ├── layout │ ├── about_preference_layout.xml │ ├── change_log_entry.xml │ ├── copy_file_dialog.xml │ ├── dialog_preference.xml │ ├── file_system_layout.xml │ ├── fix_dialog.xml │ ├── folder_browser_dialog.xml │ ├── main.xml │ ├── onscripter.xml │ ├── radiobutton_choice_item.xml │ ├── sdcard_fix_su_dialog.xml │ ├── selective_file_dialog.xml │ ├── selective_file_item.xml │ ├── vnsettings_dialog.xml │ ├── vnsettings_dialog_controls.xml │ └── vnsettings_dialog_text.xml │ ├── menu │ └── menu_launcher.xml │ ├── values-ja │ ├── change_log.xml │ └── strings.xml │ ├── values-ko │ ├── change_log.xml │ └── strings.xml │ ├── values-ru │ ├── change_log.xml │ └── strings.xml │ ├── values-xlarge │ └── dimens.xml │ ├── values-zh │ ├── change_log.xml │ └── strings.xml │ ├── values │ ├── attrs.xml │ ├── change_log.xml │ ├── dimens.xml │ ├── hidden_strings.xml │ ├── strings.xml │ ├── style.xml │ └── themes.xml │ └── xml │ ├── about_settings.xml │ ├── general_settings.xml │ └── settings_header.xml ├── build.gradle ├── design ├── buttons.psd ├── feature-image.psd ├── folder.psd ├── icon.psd └── screenshots │ ├── ja │ ├── screenshot1.png │ ├── screenshot2.png │ ├── screenshot3.png │ ├── screenshot4.png │ ├── screenshot5.png │ └── screenshot6.png │ ├── ko │ ├── screenshot1.png │ ├── screenshot2.png │ ├── screenshot3.png │ ├── screenshot4.png │ └── screenshot5.png │ ├── ru │ ├── screenshot1.png │ ├── screenshot2.png │ ├── screenshot3.png │ ├── screenshot4.png │ ├── screenshot5.png │ └── screenshot6.png │ ├── screenshot1.png │ ├── screenshot2.png │ ├── screenshot3.png │ ├── screenshot4.png │ ├── screenshot5.png │ ├── screenshot6.png │ ├── screenshot7.png │ └── screenshot8.png ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | build/ 3 | obj/ 4 | 5 | # Crashlytics configuations 6 | com_crashlytics_export_strings.xml 7 | 8 | # Local configuration file (sdk path, etc) 9 | local.properties 10 | 11 | # Gradle generated files 12 | .gradle/ 13 | 14 | # Signing files 15 | .signing/ 16 | 17 | # User-specific configurations 18 | .idea/libraries/ 19 | .idea/workspace.xml 20 | .idea/tasks.xml 21 | .idea/.name 22 | .idea/compiler.xml 23 | .idea/copyright/profiles_settings.xml 24 | .idea/encodings.xml 25 | .idea/misc.xml 26 | .idea/modules.xml 27 | .idea/scopes/scope_settings.xml 28 | .idea/vcs.xml 29 | *.iml 30 | 31 | # OS-specific files 32 | .DS_Store 33 | .DS_Store? 34 | ._* 35 | .Spotlight-V100 36 | .Trashes 37 | ehthumbs.db 38 | Thumbs.db 39 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libs/VPlayer_lib"] 2 | path = VPlayer_lib 3 | url = git@github.com:matthewn4444/VPlayer_lib.git 4 | [submodule "libs/onscripter-engine-android"] 5 | path = onscripter-engine-android 6 | url = git@github.com:matthewn4444/onscripter-engine-android.git 7 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | This repository is not active anymore. (Oct 18, 2021) 2 | 3 | =========================== 4 | Onscripter Plus For Android 5 | =========================== 6 | December 27, 2013 7 | 8 | Fork of Onscripter for Android (http://onscripter.sourceforge.jp/android/android.html) 9 | that is compiled on Windows including full source (with dependencies). 10 | 11 | This Android application allows you to play visual novel games using the NScripter engine 12 | on your Android device. 13 | 14 | 15 | Steps to Compile 16 | ================ 17 | 1. Install Java [https://www.java.com/en/] (match bit with Eclipse, probably get 32-bit) 18 | 2. Install Eclipse with Android SDK [https://developer.android.com/sdk/index.html] (32bit probably) 19 | 3. Run the "Android SDK Manager" and install: 20 | - Tools/ - All 21 | - Android 2.2 (API 8) - All 22 | - Extras/ -> Support Repo, Support Library, Google USB Driver, Google Web Driver 23 | - [OPTIONAL] Android 4.0 (API 14) and/or anything newer 24 | 4. [WINDOWS] Install Cywin [http://cygwin.com/install.html] 25 | - When choosing what to install, only install: 26 | DLevel -> make 27 | 5. [WINDOWS] Set up the environment variable for cygwin in PATH (to the bin folder) 28 | C:\/bin; 29 | 6. Install the NDK [http://developer.android.com/tools/sdk/ndk/index.html] (Doesn't matter the bit) 30 | 7. Setup NDK in Eclipse: 31 | - Open Eclipse 32 | - Window -> Preference -> Android -> NDK -> [Browse the location of the NDK folder] 33 | C:\\android-ndk 34 | 8. Git clone this repo a folder 35 | 9. Open Eclipse and Import the project 36 | - Open Eclipse 37 | - File -> Import... -> Android -> Existing Android Code Into Workspace -> [Then find the repo] 38 | 10. Add Native Support to project: 39 | - Right click ONScripterPlus -> Android Tools -> Add Native Support (If no option, then you already have native support) 40 | 11. [WINDOWS] Open file "/jni/application/Android.mk" 41 | - Change the part of APP_SUBDIR of "C:\Programming\cygwin64\bin\find" to cygwin "find" 42 | 11. [WINDOWS] Open file "/jni/freetype/Android.mk" 43 | - Change the part of APP_SUBDIR of "C:\Programming\cygwin64\bin\find" to cygwin "find" 44 | 11. Build the project (ONScipter takes a while to build) and run on device 45 | 46 | 47 | Change version of ONScripter 48 | ============================ 49 | 1. Download new version of ONScripter source code based on your operating system from http://onscripter.sourceforge.jp/onscripter.html 50 | 2. Delete the folder "/jni/application/onscripter-*" (e.g. /onscripter-20130202) 51 | 3. Extract the folder "onscripter-*" (e.g. onscripter-20130202) source into "/jni/application" 52 | 4. Rebuild the code from Eclipse 53 | 54 | 55 | Play Visual Novel 56 | ================= 57 | 1. Download a visual novel game that uses NScripter 58 | 2. Plug Android device in computer and navigate to the internal memory of the Android device 59 | 3. Make a new folder "ons" 60 | 4. Place the game folder into "ons" folder 61 | 5. [OPTIONAL] Place a font (Japanese preferably) into the game folder and name it "default.ttf" 62 | - if no font is provided, it will use a default font 63 | 6. You can delete the dll files 64 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 22 5 | buildToolsVersion "22.0.1" 6 | 7 | defaultConfig { 8 | applicationId "com.onscripter.plus" 9 | minSdkVersion 16 10 | targetSdkVersion 22 11 | versionCode 6 12 | versionName "1.2.4" 13 | } 14 | 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | } 22 | 23 | dependencies { 24 | compile fileTree(dir: 'libs', include: ['*.jar']) 25 | compile project(':onscripter-engine-android') 26 | compile project(':VPlayer_library') 27 | compile files('src/main/libs/android-support-v4.jar') 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 | 23 | 24 | 25 | 26 | 27 | 28 | 33 | 34 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /app/src/main/assets/fonts/default-1.1.7.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/assets/fonts/default-1.1.7.ttf -------------------------------------------------------------------------------- /app/src/main/java/com/onscripter/plus/ActivityPlus.java: -------------------------------------------------------------------------------- 1 | package com.onscripter.plus; 2 | 3 | import android.support.v4.app.FragmentActivity; 4 | 5 | 6 | public abstract class ActivityPlus extends FragmentActivity { 7 | 8 | private OnLifeCycleListener mListener; 9 | 10 | public static abstract class OnLifeCycleListener { 11 | public void onStart() {} 12 | public void onStop() {} 13 | public void onPause() {} 14 | public void onResume() {} 15 | public void onRestart() {} 16 | public void onBackPressed() {} 17 | public void onDestroy() {} 18 | } 19 | 20 | public void setOnLifeCycleListener(OnLifeCycleListener listener) { 21 | mListener = listener; 22 | } 23 | 24 | @Override 25 | protected void onStart() { 26 | super.onStart(); 27 | if (mListener != null) { 28 | mListener.onStart(); 29 | } 30 | } 31 | 32 | @Override 33 | protected void onStop() { 34 | super.onStop(); 35 | if (mListener != null) { 36 | mListener.onStart(); 37 | } 38 | } 39 | 40 | @Override 41 | protected void onPause() { 42 | super.onPause(); 43 | if (mListener != null) { 44 | mListener.onPause(); 45 | } 46 | } 47 | 48 | @Override 49 | protected void onRestart() { 50 | super.onRestart(); 51 | if (mListener != null) { 52 | mListener.onRestart(); 53 | } 54 | } 55 | 56 | @Override 57 | protected void onResume() { 58 | super.onResume(); 59 | if (mListener != null) { 60 | mListener.onResume(); 61 | } 62 | } 63 | 64 | @Override 65 | public void onBackPressed() { 66 | super.onBackPressed(); 67 | if (mListener != null) { 68 | mListener.onBackPressed(); 69 | } 70 | } 71 | 72 | @Override 73 | protected void onDestroy() { 74 | super.onDestroy(); 75 | if (mListener != null) { 76 | mListener.onDestroy(); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /app/src/main/java/com/onscripter/plus/App.java: -------------------------------------------------------------------------------- 1 | package com.onscripter.plus; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | 6 | public final class App extends Application { 7 | private static Context StaticContext; 8 | 9 | @Override 10 | public void onCreate() { 11 | super.onCreate(); 12 | StaticContext = this; 13 | } 14 | 15 | public static Context getContext() { 16 | return StaticContext; 17 | } 18 | 19 | public static String string(int resId) { 20 | return StaticContext.getString(resId); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/onscripter/plus/ChangeLog.java: -------------------------------------------------------------------------------- 1 | package com.onscripter.plus; 2 | 3 | import java.io.File; 4 | import java.util.ArrayList; 5 | import java.util.Calendar; 6 | import java.util.Locale; 7 | 8 | import android.app.Activity; 9 | import android.app.AlertDialog; 10 | import android.app.AlertDialog.Builder; 11 | import android.content.DialogInterface; 12 | import android.content.Intent; 13 | import android.content.SharedPreferences; 14 | import android.content.SharedPreferences.Editor; 15 | import android.content.pm.ApplicationInfo; 16 | import android.content.pm.PackageManager.NameNotFoundException; 17 | import android.net.Uri; 18 | import android.preference.PreferenceManager; 19 | import android.text.Html; 20 | import android.text.method.LinkMovementMethod; 21 | import android.view.View; 22 | import android.widget.LinearLayout; 23 | import android.widget.LinearLayout.LayoutParams; 24 | import android.widget.ListView; 25 | import android.widget.TextView; 26 | 27 | public class ChangeLog { 28 | private AlertDialog mDialog; 29 | private final Activity mCtx; 30 | private final SharedPreferences mPref; 31 | private ListView mList; 32 | private static String PREF_KEY = null; 33 | private static String BULLET_POINT = null; 34 | 35 | public ChangeLog(Activity ctx) { 36 | mPref = PreferenceManager.getDefaultSharedPreferences(ctx); 37 | mCtx = ctx; 38 | if (PREF_KEY == null) { 39 | PREF_KEY = ctx.getString(R.string.change_log_key); 40 | BULLET_POINT = ctx.getString(R.string.bullet_point); 41 | } 42 | LauncherActivity.log(1); 43 | long lastDate = mPref.getLong(PREF_KEY, 0); 44 | try { 45 | ApplicationInfo appInfo = ctx.getPackageManager() 46 | .getApplicationInfo(ctx.getPackageName(), 0); 47 | String appFile = appInfo.sourceDir; 48 | LauncherActivity.log(1); 49 | long installed = new File(appFile).lastModified(); 50 | LauncherActivity.log(lastDate < installed, lastDate, installed); 51 | if (lastDate < installed) { 52 | // Show the change log 53 | show(); 54 | } 55 | } catch (NameNotFoundException e) { 56 | e.printStackTrace(); 57 | } 58 | } 59 | 60 | public void show() { 61 | if (mDialog == null) { 62 | AlertDialog.Builder b = new Builder(mCtx); 63 | b.setNeutralButton(android.R.string.ok, 64 | new DialogInterface.OnClickListener() { 65 | @Override 66 | public void onClick(DialogInterface dialog, int which) { 67 | setChangeLogTimestamp(); 68 | } 69 | }); 70 | mList = new ListView(mCtx); 71 | b.setPositiveButton(R.string.dialog_button_rate, 72 | new DialogInterface.OnClickListener() { 73 | @Override 74 | public void onClick(DialogInterface dialog, int which) { 75 | showThisAppInMarket(); 76 | setChangeLogTimestamp(); 77 | } 78 | }); 79 | 80 | LinearLayout layout = new LinearLayout(mCtx); 81 | layout.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); 82 | int padding = (int)mCtx.getResources().getDimension(R.dimen.change_log_padding); 83 | layout.setPadding(padding, padding, padding, padding); 84 | layout.setOrientation(LinearLayout.VERTICAL); 85 | 86 | // If displaying English, then add the message to add translation 87 | String lang = Locale.getDefault().getLanguage(); 88 | if (!lang.equals(Locale.JAPANESE.toString()) && !lang.equals(Locale.KOREAN.toString()) 89 | && !lang.equals(Locale.CHINESE.toString())) { 90 | layout.setPadding(padding, padding, padding, padding); 91 | TextView emailText = new TextView(mCtx); 92 | TextView translationText = new TextView(mCtx); 93 | emailText.setMovementMethod(LinkMovementMethod.getInstance()); 94 | String email = mCtx.getString(R.string.email); 95 | emailText.setText(Html.fromHtml("" + email + "")); 96 | translationText.setText(Html.fromHtml(mCtx.getString(R.string.dialog_add_translation))); 97 | layout.addView(translationText); 98 | layout.addView(emailText); 99 | } else { 100 | layout.setPadding(padding, 0, padding, 0); 101 | } 102 | layout.addView(mList); 103 | b.setView(layout); 104 | b.setTitle(R.string.change_log_dialog_title); 105 | b.setCancelable(false); 106 | buildContents(); 107 | mDialog = b.create(); 108 | } 109 | mDialog.show(); 110 | } 111 | 112 | public void hide() { 113 | if (mDialog != null) { 114 | mDialog.hide(); 115 | } 116 | } 117 | 118 | private void showAppInMarket(String packageName) { 119 | try { 120 | mCtx.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + packageName))); 121 | } catch (android.content.ActivityNotFoundException anfe) { 122 | mCtx.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://play.google.com/store/apps/details?id=" + packageName))); 123 | } 124 | } 125 | 126 | private void showThisAppInMarket() { 127 | final String appPackageName = mCtx.getApplicationContext().getPackageName(); 128 | showAppInMarket(appPackageName); 129 | } 130 | 131 | private void setChangeLogTimestamp() { 132 | Editor editor = mPref.edit(); 133 | editor.putLong(PREF_KEY, Calendar.getInstance().getTimeInMillis()); 134 | editor.apply(); 135 | } 136 | 137 | private void buildContents() { 138 | ArrayList entries = new ArrayList(); 139 | String[] info = mCtx.getResources().getStringArray(R.array.change_log); 140 | 141 | // Build the list of entries 142 | Entry currentEntry = null; 143 | for (int i = 0; i < info.length; i++) { 144 | String line = info[i]; 145 | if (line.startsWith("v")) { 146 | if (currentEntry != null) { 147 | entries.add(currentEntry); 148 | } 149 | 150 | // Parse new version number 151 | currentEntry = new Entry(); 152 | String[] items = line.split(","); 153 | currentEntry.versionName = items[0].substring(1, items[0].length()); 154 | currentEntry.dateStr = items[1]; 155 | } else if (currentEntry != null) { 156 | currentEntry.changeList.add(line); 157 | } 158 | } 159 | if (currentEntry != null) { 160 | entries.add(currentEntry); 161 | } 162 | 163 | ChangeLogAdapter adapter = new ChangeLogAdapter(mCtx, entries); 164 | mList.setAdapter(adapter); 165 | mList.setSelector(android.R.color.transparent); 166 | } 167 | 168 | private class Entry { 169 | public String dateStr; 170 | public String versionName; 171 | public ArrayList changeList = new ArrayList(); 172 | } 173 | 174 | private static int[] WIDGET_IDS = { R.id.version, R.id.date, R.id.data }; 175 | 176 | private class ChangeLogAdapter extends ViewAdapterBase { 177 | public ChangeLogAdapter(Activity a, ArrayList list) { 178 | super(a, R.layout.change_log_entry, WIDGET_IDS, list); 179 | } 180 | 181 | @Override 182 | protected void setWidgetValues(int position, Entry item, 183 | View[] elements, View layout) { 184 | ((TextView)elements[0]).setText(item.versionName); 185 | ((TextView)elements[1]).setText(item.dateStr); 186 | 187 | // Build the list of changes 188 | if (item.changeList.size() > 0) { 189 | StringBuilder sb = new StringBuilder(); 190 | sb.append('\t').append(BULLET_POINT).append(' ').append(item.changeList.get(0)); 191 | for (int i = 1; i < item.changeList.size(); i++) { 192 | sb.append('\n').append('\t').append(BULLET_POINT).append(' ') 193 | .append(item.changeList.get(i)); 194 | } 195 | ((TextView)elements[2]).setText(sb); 196 | elements[2].setVisibility(View.VISIBLE); 197 | } else { 198 | elements[2].setVisibility(View.GONE); 199 | } 200 | } 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /app/src/main/java/com/onscripter/plus/DataDownloader.java: -------------------------------------------------------------------------------- 1 | package com.onscripter.plus; 2 | 3 | import android.os.Bundle; 4 | import android.os.Message; 5 | import android.os.Handler; 6 | 7 | import org.apache.http.impl.client.DefaultHttpClient; 8 | import org.apache.http.client.methods.HttpGet; 9 | import org.apache.http.HttpResponse; 10 | import org.apache.http.HttpStatus; 11 | import org.apache.http.params.HttpConnectionParams; 12 | 13 | import java.io.File; 14 | import java.io.FileInputStream; 15 | import java.io.FileOutputStream; 16 | import java.io.BufferedInputStream; 17 | import java.io.BufferedOutputStream; 18 | import java.io.IOException; 19 | 20 | import java.util.List; 21 | import java.util.Iterator; 22 | import java.util.Arrays; 23 | import java.util.zip.ZipInputStream; 24 | import java.util.zip.ZipEntry; 25 | import java.util.zip.CheckedInputStream; 26 | import java.util.zip.CRC32; 27 | 28 | public class DataDownloader extends Thread 29 | { 30 | private byte[] buf = null; 31 | 32 | public DataDownloader( String zip_dir, String zip_filename, String extract_dir, String version_filename, String url, long file_size, Handler h ) 33 | { 34 | this.zip_dir = zip_dir; 35 | this.zip_filename = zip_filename; 36 | this.extract_dir = extract_dir; 37 | this.version_filename = version_filename; 38 | this.url = url; 39 | this.file_size = file_size; 40 | handler = h; 41 | buf = new byte[8192*2]; 42 | 43 | this.start(); 44 | } 45 | 46 | @Override 47 | public void run() 48 | { 49 | File file = new File(zip_dir); 50 | try { 51 | file.mkdirs(); 52 | } 53 | catch( SecurityException e ){ 54 | sendMessage(-2, 0, "Failed to create root directory: " + e.toString()); 55 | return; 56 | } 57 | 58 | String zip_path = zip_dir + "/" + zip_filename; 59 | 60 | file = new File(zip_path); 61 | if (file.exists() == false || file.length() != file_size) 62 | if (downloadZip(zip_path) != 0) return; 63 | 64 | if (extractZip(zip_path) != 0) return; 65 | 66 | if (file_size == -1){ 67 | file = new File(zip_path); 68 | try { 69 | file.delete(); 70 | } 71 | catch( SecurityException e ){ 72 | sendMessage(-2, 0, "Failed to delete temporary file: " + e.toString()); 73 | return; 74 | } 75 | } 76 | 77 | file = new File(extract_dir + "/" + version_filename); 78 | try { 79 | file.createNewFile(); 80 | } catch( Exception e ) { 81 | sendMessage(-2, 0, "Failed to create version file: " + e.toString()); 82 | return; 83 | }; 84 | 85 | sendMessage(-1, 0, null); 86 | } 87 | 88 | private int downloadZip(String zip_path) 89 | { 90 | HttpResponse response = null; 91 | HttpGet request; 92 | int retry = 0; 93 | 94 | BufferedOutputStream tmp_out = null; 95 | long downloaded = 0; 96 | long totalLen = 0; 97 | while(true){ 98 | DefaultHttpClient client = null; 99 | request = new HttpGet(url); 100 | request.addHeader("Accept", "*/*"); 101 | if (totalLen > 0) request.addHeader("Range", "bytes="+downloaded+"-"+totalLen); 102 | try { 103 | client = new DefaultHttpClient(); 104 | client.getParams().setBooleanParameter("http.protocol.handle-redirects", true); 105 | HttpConnectionParams.setConnectionTimeout(client.getParams(), 5000); 106 | HttpConnectionParams.setSoTimeout(client.getParams(), 3000); 107 | response = client.execute(request); 108 | } catch (org.apache.http.conn.ConnectTimeoutException e) { 109 | retry++; 110 | continue; 111 | } catch (java.net.SocketException e) { 112 | retry++; 113 | continue; 114 | } catch (java.net.SocketTimeoutException e) { 115 | retry++; 116 | continue; 117 | } catch (IOException e) { 118 | sendMessage(-2, 0, "Timeout or zip file is not found: " + e.toString()); 119 | return -1; 120 | }; 121 | 122 | if (response == null || 123 | (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK && 124 | response.getStatusLine().getStatusCode() != HttpStatus.SC_PARTIAL_CONTENT)){ 125 | response = null; 126 | sendMessage(-2, 0, "Timeout or zip file is not found."); 127 | return -1; 128 | } 129 | 130 | totalLen = response.getEntity().getContentLength(); 131 | if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK){ 132 | downloaded = 0; 133 | try { 134 | if (tmp_out != null){ 135 | tmp_out.flush(); 136 | tmp_out.close(); 137 | tmp_out = null; 138 | } 139 | tmp_out = new BufferedOutputStream(new FileOutputStream(zip_path)); 140 | } catch( Exception e ) { 141 | sendMessage(-2, 0, "Failed to create temporary file: " + e.toString()); 142 | return -1; 143 | }; 144 | } 145 | else{ 146 | totalLen += downloaded; 147 | } 148 | 149 | BufferedInputStream stream = null; 150 | try { 151 | stream = new BufferedInputStream(response.getEntity().getContent()); 152 | } catch( java.io.IOException e ) { 153 | client.getConnectionManager().shutdown(); 154 | retry++; 155 | continue; 156 | } catch( java.lang.IllegalStateException e ) { 157 | client.getConnectionManager().shutdown(); 158 | retry++; 159 | continue; 160 | } 161 | 162 | try { 163 | int len = stream.read(buf); 164 | while (len >= 0){ 165 | if (len > 0) tmp_out.write(buf, 0, len); 166 | downloaded += len; 167 | sendMessage((int)downloaded, (int)totalLen, "Downloading archives from Internet: retry " + retry); 168 | len = stream.read(buf); 169 | try{ 170 | Thread.sleep(1); 171 | } catch (InterruptedException e){ 172 | } 173 | } 174 | } catch (java.net.SocketException e) { 175 | } catch( java.net.SocketTimeoutException e ) { 176 | } catch( java.io.IOException e ) { 177 | sendMessage(-2, 0, "Failed to write or download: " + e.toString()); 178 | return -1; 179 | } 180 | 181 | try { 182 | stream.close(); 183 | stream = null; 184 | } catch( java.io.IOException e ) { 185 | }; 186 | 187 | client.getConnectionManager().shutdown(); 188 | 189 | if (downloaded == totalLen) break; 190 | retry++; 191 | } 192 | 193 | try { 194 | tmp_out.flush(); 195 | tmp_out.close(); 196 | tmp_out = null; 197 | } catch( java.io.IOException e ) { 198 | }; 199 | 200 | return 0; 201 | } 202 | 203 | private int extractZip(String zip_path) 204 | { 205 | ZipInputStream zip = null; 206 | try { 207 | zip = new ZipInputStream(new BufferedInputStream(new FileInputStream(zip_path))); 208 | } catch( java.io.FileNotFoundException e ) { 209 | sendMessage(-2, 0, "Failed to read from zip file: " + e.toString()); 210 | return -1; 211 | }; 212 | 213 | int num_file = 0; 214 | while(true){ 215 | num_file++; 216 | ZipEntry entry = null; 217 | try { 218 | entry = zip.getNextEntry(); 219 | } catch( java.io.IOException e ) { 220 | sendMessage(-2, 0, "Failed to get entry from zip file: " + e.toString()); 221 | return -1; 222 | } 223 | if (entry == null) break; 224 | 225 | String path = extract_dir + "/" + entry.getName(); 226 | if (entry.isDirectory()){ 227 | try { 228 | (new File( path )).mkdirs(); 229 | } catch( SecurityException e ) { 230 | sendMessage(-2, 0, "Failed to create directory: " + e.toString()); 231 | return -1; 232 | } 233 | continue; 234 | } 235 | 236 | try { 237 | (new File( path.substring(0, path.lastIndexOf("/") ))).mkdirs(); 238 | } catch( SecurityException e ){ 239 | sendMessage(-2, 0, "Failed to create directory: " + e.toString()); 240 | return -1; 241 | }; 242 | 243 | if (extractZipEntry(path, zip, (int)entry.getSize(), "Extracting archives: " + num_file) != 0) return -1; 244 | 245 | try { 246 | CheckedInputStream check = new CheckedInputStream( new FileInputStream(path), new CRC32() ); 247 | while( check.read(buf) > 0 ) {}; 248 | check.close(); 249 | if (check.getChecksum().getValue() != entry.getCrc()){ 250 | File ff = new File(path); 251 | ff.delete(); 252 | throw new Exception(); 253 | } 254 | } catch( Exception e ){ 255 | sendMessage(-2, 0, "CRC check failed"); 256 | return -1; 257 | } 258 | } 259 | 260 | return 0; 261 | } 262 | 263 | private int extractZipEntry(String out_path, ZipInputStream zip, int total_size, String mes) 264 | { 265 | BufferedOutputStream out = null; 266 | try { 267 | out = new BufferedOutputStream(new FileOutputStream( out_path )); 268 | } catch( Exception e ) { 269 | sendMessage(-2, 0, "Failed to create file: " + e.toString()); 270 | return -1; 271 | }; 272 | 273 | int total_read = 0; 274 | try { 275 | int len = zip.read(buf); 276 | while (len >= 0){ 277 | if (len > 0) out.write(buf, 0, len); 278 | total_read += len; 279 | sendMessage(total_read, total_size, mes); 280 | len = zip.read(buf); 281 | try{ 282 | Thread.sleep(1); 283 | } catch (InterruptedException e){ 284 | } 285 | } 286 | out.flush(); 287 | out.close(); 288 | } catch( java.io.IOException e ) { 289 | sendMessage(-2, 0, "Failed to write: " + e.toString()); 290 | return -1; 291 | } 292 | 293 | return 0; 294 | } 295 | 296 | public void sendMessage(int current, int total, String str){ 297 | Message msg = handler.obtainMessage(); 298 | Bundle b = new Bundle(); 299 | b.putInt("total", total); 300 | b.putInt("current", current); 301 | b.putString("message", str); 302 | msg.setData(b); 303 | handler.sendMessage(msg); 304 | } 305 | 306 | private String zip_dir = null; 307 | private String zip_filename = null; 308 | private String extract_dir = null; 309 | private String version_filename = null; 310 | private String url = null; 311 | private long file_size = -1; 312 | private Handler handler = null; 313 | } 314 | -------------------------------------------------------------------------------- /app/src/main/java/com/onscripter/plus/Environment2.java: -------------------------------------------------------------------------------- 1 | package com.onscripter.plus; 2 | 3 | import java.io.File; 4 | import java.io.FileFilter; 5 | 6 | import android.annotation.SuppressLint; 7 | import android.os.Environment; 8 | 9 | public final class Environment2 { 10 | 11 | // List of all potential external sd card paths 12 | @SuppressLint("SdCardPath") 13 | private final static String[] EXTERNAL_SD_DIR = { 14 | "/mnt/external", 15 | "/mnt/sdcard/external_sd", 16 | "/mnt/sdcard/ext_sd", 17 | "/mnt/external_sd", 18 | "/mnt/ext_sd", 19 | "/mnt/ext_sdcard", 20 | "/mnt/extSdCard", 21 | "/mnt/ext_card", 22 | "/mnt/extsd", 23 | "/mnt/sdcard-ext", 24 | "/mnt/sdcard2", 25 | "/storage/sdcard1/", 26 | "/storage/external_SD", 27 | "/storage/MicroSD", 28 | "/sdcard2", 29 | "/storage/ext_sd", 30 | "/sdcard0", 31 | "/mnt/sdcard0", 32 | "/mnt/sdcard/", 33 | }; 34 | private static boolean HasScanned = false; 35 | 36 | // Private constructor so it is not used 37 | private Environment2(){} 38 | 39 | // Cached locations 40 | private static File InternalStorageFile; 41 | private static File ExternalSDCardStorageFile; 42 | 43 | static public File getInternalStorageDirectory() { 44 | verifyInternalStorage(); 45 | return InternalStorageFile; 46 | } 47 | 48 | static public File getExternalSDCardDirectory() { 49 | verifyExternalSDCard(); 50 | return ExternalSDCardStorageFile; 51 | } 52 | 53 | static public boolean hasInternalStorage() { 54 | verifyInternalStorage(); 55 | return InternalStorageFile != null; 56 | } 57 | 58 | static public boolean hasExternalSDCard() { 59 | verifyExternalSDCard(); 60 | return ExternalSDCardStorageFile != null; 61 | } 62 | 63 | // Checks to see if the file exists before returning, also rescans if anything may have gone wrong 64 | static private void verifyInternalStorage() { 65 | if (!HasScanned && InternalStorageFile == null || 66 | InternalStorageFile != null && !InternalStorageFile.exists()) { 67 | reScan(); 68 | } 69 | } 70 | 71 | // Checks to see if the file exists before returning, also rescans if anything may have gone wrong 72 | static private void verifyExternalSDCard() { 73 | if (!HasScanned && ExternalSDCardStorageFile == null || 74 | ExternalSDCardStorageFile != null && !ExternalSDCardStorageFile.exists()) { 75 | reScan(); 76 | } 77 | } 78 | 79 | // Rescans the potential locations for storage 80 | static public void reScan() { 81 | ExternalSDCardStorageFile = null; 82 | InternalStorageFile = Environment.getExternalStorageDirectory(); 83 | 84 | // Scan storage for XXXX-XXXX folder pattern that should represent the sdcard 85 | File storage = new File("/storage"); 86 | if (ExternalSDCardStorageFile == null && storage.exists() && storage.canRead()) { 87 | File[] files = storage.listFiles(new FileFilter() { 88 | @Override 89 | public boolean accept(File pathname) { 90 | return pathname.getName().matches("[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}"); 91 | } 92 | }); 93 | for (File file: files) { 94 | if (file.canRead()) { 95 | ExternalSDCardStorageFile = file; 96 | break; 97 | } 98 | } 99 | } 100 | 101 | if (ExternalSDCardStorageFile == null) { 102 | for (int i = 0; i < EXTERNAL_SD_DIR.length; i++) { 103 | File file = new File(EXTERNAL_SD_DIR[i]); 104 | if (file != null && file.exists() && !file.equals(InternalStorageFile) // Directory must exist and not be internal memory 105 | && file.length() > 0) { 106 | // Directory also must have space and files 107 | String[] fileList = file.list(); 108 | if (fileList != null && fileList.length > 0) { 109 | ExternalSDCardStorageFile = file; 110 | break; 111 | } 112 | } 113 | } 114 | } 115 | 116 | HasScanned = true; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /app/src/main/java/com/onscripter/plus/FolderBrowserDialogPreference.java: -------------------------------------------------------------------------------- 1 | package com.onscripter.plus; 2 | 3 | import android.content.Context; 4 | import android.content.DialogInterface; 5 | import android.content.res.TypedArray; 6 | import android.os.Bundle; 7 | import android.os.Parcel; 8 | import android.os.Parcelable; 9 | import android.preference.DialogPreference; 10 | import android.util.AttributeSet; 11 | import android.util.TypedValue; 12 | import android.view.View; 13 | import android.view.ViewGroup; 14 | 15 | public class FolderBrowserDialogPreference extends DialogPreference { 16 | private final FolderBrowserDialogWrapper mWrapper; 17 | 18 | public FolderBrowserDialogPreference(Context context, AttributeSet attrs) { 19 | this(context, attrs, 0); 20 | } 21 | 22 | public FolderBrowserDialogPreference(Context context, AttributeSet attrs, int defStyle) { 23 | super(context, attrs, defStyle); 24 | mWrapper = new FolderBrowserDialogWrapper(context); 25 | 26 | setPositiveButtonText(R.string.dialog_select_button_text); 27 | setNegativeButtonText(android.R.string.cancel); 28 | setLayoutResource(R.layout.dialog_preference); 29 | } 30 | 31 | @Override 32 | protected View onCreateView(ViewGroup parent) { 33 | View v = super.onCreateView(parent); 34 | int paddingLeft = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 35 | v.getResources().getDimension(R.dimen.preference_padding_start), 36 | v.getResources().getDisplayMetrics()); 37 | v.setPadding(paddingLeft, 0, 0, 0); 38 | return v; 39 | } 40 | 41 | @Override 42 | protected View onCreateDialogView() { 43 | return mWrapper.getDialogLayout(); 44 | } 45 | 46 | @Override 47 | protected void showDialog(Bundle state) { 48 | super.showDialog(state); 49 | mWrapper.setDialog(getDialog()); 50 | mWrapper.show(getPersistedString(null)); 51 | } 52 | 53 | @Override 54 | public void onDismiss(DialogInterface dialog) { 55 | ViewGroup layout = mWrapper.getDialogLayout(); 56 | if (layout.getParent() != null) { 57 | ((ViewGroup)layout.getParent()).removeView(layout); 58 | } 59 | super.onDismiss(dialog); 60 | } 61 | 62 | @Override 63 | protected void onDialogClosed(boolean positiveResult) { 64 | super.onDialogClosed(positiveResult); 65 | 66 | if (positiveResult) { 67 | String value = mWrapper.getResultDirectory().getPath(); 68 | if (callChangeListener(value)) { 69 | persistString(value); 70 | } 71 | } 72 | } 73 | 74 | @Override 75 | protected Object onGetDefaultValue(TypedArray a, int index) { 76 | return a.getString(index); 77 | } 78 | 79 | // Code below is from EditTextPreference class 80 | @Override 81 | protected Parcelable onSaveInstanceState() { 82 | final Parcelable superState = super.onSaveInstanceState(); 83 | if (isPersistent()) { 84 | // No need to save instance state since it's persistent 85 | return superState; 86 | } 87 | 88 | final SavedState myState = new SavedState(superState); 89 | myState.text = mWrapper.getResultDirectory().getPath(); 90 | return myState; 91 | } 92 | 93 | @Override 94 | protected void onRestoreInstanceState(Parcelable state) { 95 | if (state == null || !state.getClass().equals(SavedState.class)) { 96 | // Didn't save state for us in onSaveInstanceState 97 | super.onRestoreInstanceState(state); 98 | return; 99 | } 100 | 101 | SavedState myState = (SavedState) state; 102 | super.onRestoreInstanceState(myState.getSuperState()); 103 | mWrapper.setupDirectories(myState.text); 104 | } 105 | 106 | private static class SavedState extends BaseSavedState { 107 | String text; 108 | 109 | public SavedState(Parcel source) { 110 | super(source); 111 | text = source.readString(); 112 | } 113 | 114 | @Override 115 | public void writeToParcel(Parcel dest, int flags) { 116 | super.writeToParcel(dest, flags); 117 | dest.writeString(text); 118 | } 119 | 120 | public SavedState(Parcelable superState) { 121 | super(superState); 122 | } 123 | 124 | public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { 125 | @Override 126 | public SavedState createFromParcel(Parcel in) { 127 | return new SavedState(in); 128 | } 129 | 130 | @Override 131 | public SavedState[] newArray(int size) { 132 | return new SavedState[size]; 133 | } 134 | }; 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /app/src/main/java/com/onscripter/plus/FolderBrowserDialogWrapper.java: -------------------------------------------------------------------------------- 1 | package com.onscripter.plus; 2 | 3 | import java.io.File; 4 | import java.io.FileNotFoundException; 5 | 6 | import android.app.AlertDialog; 7 | import android.app.Dialog; 8 | import android.content.Context; 9 | import android.content.DialogInterface; 10 | import android.content.DialogInterface.OnKeyListener; 11 | import android.content.res.TypedArray; 12 | import android.graphics.drawable.Drawable; 13 | import android.os.Environment; 14 | import android.text.method.TextKeyListener; 15 | import android.view.Display; 16 | import android.view.KeyEvent; 17 | import android.view.LayoutInflater; 18 | import android.view.View; 19 | import android.view.ViewGroup; 20 | import android.view.WindowManager; 21 | import android.widget.AdapterView; 22 | import android.widget.AdapterView.OnItemClickListener; 23 | import android.widget.EditText; 24 | import android.widget.ImageButton; 25 | import android.widget.LinearLayout; 26 | import android.widget.ListView; 27 | import android.widget.TextView; 28 | import android.widget.Toast; 29 | 30 | public class FolderBrowserDialogWrapper implements OnItemClickListener, OnKeyListener { 31 | private final LinearLayout mLayout; 32 | private final ListView mListView; 33 | private FileSystemAdapter mAdapter; 34 | private final Context mCtx; 35 | private final TextView mPathText; 36 | private final ImageButton mTogglePath; 37 | private final ImageButton mNewFolderButton; 38 | private final TextView mExternalNotFoundText; 39 | private final boolean mAccessExtStorage; 40 | private Dialog mDialog; 41 | private Dialog mNewFolderDialog; 42 | private boolean isInInternalStorage; 43 | 44 | private static Drawable IconPhoneDrawable; 45 | private static Drawable IconSDcardDrawable; 46 | 47 | // Files 48 | private File mCurrentInternalPath; 49 | private File mCurrentExternalPath; 50 | private static File InternalStorage; 51 | private static File ExternalStorage; 52 | 53 | public FolderBrowserDialogWrapper(Context context) { 54 | this(context, true, false); 55 | } 56 | 57 | public FolderBrowserDialogWrapper(Context context, boolean accessExternalStorage, boolean ableToMakeFolders) { 58 | mCtx = context; 59 | mAccessExtStorage = accessExternalStorage; 60 | 61 | // Inflate the dialog 62 | LayoutInflater inflater = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE); 63 | mLayout = (LinearLayout) inflater.inflate(R.layout.folder_browser_dialog, null); 64 | mListView = (ListView) mLayout.findViewById(R.id.list); 65 | mPathText = (TextView) mLayout.findViewById(R.id.path); 66 | mExternalNotFoundText = (TextView) mLayout.findViewById(R.id.extNotFound); 67 | mTogglePath = (ImageButton) mLayout.findViewById(R.id.toggleLocation); 68 | mNewFolderButton = (ImageButton) mLayout.findViewById(R.id.newFolder); 69 | mListView.setOnItemClickListener(this); 70 | mTogglePath.setOnClickListener(new View.OnClickListener() { 71 | @Override 72 | public void onClick(View v) { 73 | toggleGotoButton(); 74 | } 75 | }); 76 | if (ableToMakeFolders) { 77 | mNewFolderButton.setOnClickListener(new View.OnClickListener() { 78 | @Override 79 | public void onClick(View arg0) { 80 | final EditText input = new EditText(mCtx); 81 | if (mNewFolderDialog == null) { 82 | mNewFolderDialog = new AlertDialog.Builder(mCtx) 83 | .setTitle(R.string.dialog_create_new_folder) 84 | .setView(input) 85 | .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { 86 | @Override 87 | public void onClick(DialogInterface dialog, int whichButton) { 88 | // Folder is created 89 | String name = input.getText().toString(); 90 | if (input.length() > 0) { 91 | TextKeyListener.clear(input.getText()); 92 | } 93 | if (mAdapter.fileExists(name)) { 94 | Toast.makeText(mCtx, R.string.message_folder_exists, Toast.LENGTH_SHORT).show(); 95 | } else { 96 | mAdapter.makeDirectory(name); 97 | } 98 | } 99 | }).setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { 100 | @Override 101 | public void onClick(DialogInterface dialog, int whichButton) { 102 | } 103 | }).create(); 104 | } 105 | mNewFolderDialog.show(); 106 | } 107 | }); 108 | mNewFolderButton.setVisibility(View.VISIBLE); 109 | } else { 110 | mNewFolderButton.setVisibility(View.GONE); 111 | } 112 | 113 | // Force dialog to max height 114 | WindowManager window = (WindowManager)mCtx.getSystemService(Context.WINDOW_SERVICE); 115 | Display display = window.getDefaultDisplay(); 116 | mLayout.setMinimumHeight(display.getHeight()); 117 | 118 | if (InternalStorage == null) { 119 | InternalStorage = Environment.getExternalStorageDirectory(); 120 | ExternalStorage = Environment2.getExternalSDCardDirectory(); 121 | } 122 | if (ExternalStorage != null || mCtx.getString(R.string.dialog_ext_not_found).equals("")) { 123 | mExternalNotFoundText.setVisibility(View.GONE); 124 | } 125 | 126 | // Themed icons for this dialog 127 | int[] attrs = new int[] { R.attr.phoneImage, R.attr.sdcardImage }; 128 | TypedArray ta = context.obtainStyledAttributes(attrs); 129 | IconPhoneDrawable = ta.getDrawable(0); 130 | IconSDcardDrawable = ta.getDrawable(1); 131 | ta.recycle(); 132 | } 133 | 134 | public ViewGroup getDialogLayout() { 135 | return mLayout; 136 | } 137 | 138 | public void setDialog(Dialog dialog) { 139 | mDialog = dialog; 140 | } 141 | 142 | public void show(String directory) { 143 | if (mDialog == null) { 144 | throw new NullPointerException("Did not run setDialog() before showing."); 145 | } 146 | mDialog.setCancelable(false); 147 | mDialog.setOnKeyListener(this); 148 | setupDirectories(directory); 149 | mDialog.show(); 150 | } 151 | 152 | public void dismiss() { 153 | if (mDialog != null) { 154 | mDialog.dismiss(); 155 | } 156 | } 157 | 158 | public File getResultDirectory() { 159 | return mAdapter.getCurrentDirectory(); 160 | } 161 | 162 | public void setupDirectories(String path) { 163 | if (mDialog == null) { 164 | throw new NullPointerException("Did not run setDialog() before showing."); 165 | } 166 | // Detect if External sdcard is available, if not then remove the sdcard button and adjust the layout 167 | final LinearLayout.LayoutParams textLayout = (LinearLayout.LayoutParams) mPathText.getLayoutParams(); 168 | if (ExternalStorage == null || !mAccessExtStorage) { 169 | ((View)mTogglePath).setVisibility(View.GONE); 170 | } else { 171 | ((View)mTogglePath).setVisibility(View.VISIBLE); 172 | } 173 | mPathText.setLayoutParams(textLayout); 174 | 175 | // Open default location from preference, if cannot find, then open storage 176 | File openDir; 177 | if (path != null) { 178 | openDir = new File(path); 179 | if (!openDir.exists()) { 180 | openDir = InternalStorage; 181 | } 182 | } else { 183 | openDir = InternalStorage; 184 | } 185 | 186 | // Detect where the current directory is either from internal or external storage 187 | if (openDir.getPath().contains(InternalStorage.getPath())) { 188 | isInInternalStorage = true; 189 | mCurrentExternalPath = ExternalStorage; 190 | } else { 191 | if (!mAccessExtStorage) { 192 | throw new IllegalStateException( 193 | "Cannot set the default location to external sd card when you have no access to it."); 194 | } 195 | isInInternalStorage = false; 196 | mCurrentInternalPath = InternalStorage; 197 | mTogglePath.setImageDrawable(IconPhoneDrawable); 198 | } 199 | 200 | try { 201 | mAdapter = new FileSystemAdapter(mCtx, openDir, true, true); 202 | mAdapter.addLowerBoundFile(InternalStorage); 203 | mAdapter.addLowerBoundFile(ExternalStorage); 204 | mAdapter.refresh(); 205 | } catch (FileNotFoundException e) { 206 | e.printStackTrace(); 207 | mDialog.dismiss(); 208 | Toast.makeText(mCtx, R.string.message_cannot_find_internal_storage, Toast.LENGTH_SHORT).show(); 209 | return; 210 | } 211 | 212 | mAdapter.bindPathToTextView(mPathText); 213 | mListView.setAdapter(mAdapter); 214 | } 215 | 216 | private void toggleGotoButton() { 217 | // Toggle between the internal and external storage 218 | if (isInInternalStorage) { 219 | mCurrentInternalPath = mAdapter.getCurrentDirectory(); 220 | mTogglePath.setImageDrawable(IconPhoneDrawable); 221 | mAdapter.setCurrentDirectory(mCurrentExternalPath); 222 | } else { 223 | mCurrentExternalPath = mAdapter.getCurrentDirectory(); 224 | mTogglePath.setImageDrawable(IconSDcardDrawable); 225 | mAdapter.setCurrentDirectory(mCurrentInternalPath); 226 | } 227 | isInInternalStorage = !isInInternalStorage; 228 | } 229 | 230 | @Override 231 | public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { 232 | // Move up a directory if back is pressed and have not hit the folder upperlimit 233 | if (event.getAction() == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_BACK) { 234 | if (mAdapter.isDirectoryAtLowerBound()) { 235 | mDialog.dismiss(); 236 | } else { 237 | mAdapter.moveUp(); 238 | } 239 | } 240 | return false; 241 | } 242 | 243 | @Override 244 | public void onItemClick(AdapterView parent, View v, int position, long id) { 245 | mAdapter.setChildAsCurrent(position); 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /app/src/main/java/com/onscripter/plus/ImageButton2.java: -------------------------------------------------------------------------------- 1 | package com.onscripter.plus; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.graphics.drawable.Drawable; 6 | import android.util.AttributeSet; 7 | import android.view.MotionEvent; 8 | import android.view.View; 9 | import android.view.View.OnClickListener; 10 | import android.view.View.OnTouchListener; 11 | import android.widget.FrameLayout; 12 | import android.widget.ImageView; 13 | import android.widget.ImageView.ScaleType; 14 | 15 | public class ImageButton2 extends FrameLayout implements OnTouchListener, OnClickListener { 16 | 17 | private final static int DOWN_ALPHA = 150; 18 | private final static int NORMAL_ALPHA = 255; 19 | private final static int HOVER_ALPHA = 200; 20 | 21 | private final ImageView mImageView; 22 | private Drawable mSrcImage; 23 | private Drawable mSrcImageSelected; 24 | private OnTouchListener mTouchListener; 25 | private OnClickListener mClickListener; 26 | private boolean mSelected = false; 27 | 28 | public ImageButton2(Context context) { 29 | this(context, null, 0); 30 | } 31 | 32 | public ImageButton2(Context context, AttributeSet attrs) { 33 | this(context, attrs, 0); 34 | } 35 | 36 | public ImageButton2(Context context, AttributeSet attrs, int defStyle) { 37 | super(context, attrs, defStyle); 38 | mImageView = new ImageView(context); 39 | 40 | TypedArray a = context.obtainStyledAttributes (attrs, R.styleable.ImageButton2, 0, 0); 41 | mSrcImage = a.getDrawable(R.styleable.ImageButton2_src); 42 | mSrcImageSelected = a.getDrawable(R.styleable.ImageButton2_src_selected); 43 | a.recycle(); 44 | 45 | super.setOnTouchListener(this); 46 | mImageView.setImageDrawable(mSrcImage); 47 | 48 | mImageView.setScaleType(ScaleType.FIT_CENTER); 49 | 50 | addView(mImageView); 51 | } 52 | 53 | public void setNormalDrawable(Drawable drawable) { 54 | mSrcImage = drawable; 55 | if (!mSelected) { 56 | mImageView.setImageDrawable(drawable); 57 | } 58 | } 59 | 60 | public void setSelectedDrawable(Drawable drawable) { 61 | mSrcImageSelected = drawable; 62 | if (drawable == null) { 63 | mImageView.setImageDrawable(mSrcImage); 64 | } 65 | } 66 | 67 | @Override 68 | public void setSelected(boolean selected) { 69 | if (mSelected != selected) { 70 | mSelected = selected; 71 | if (mSrcImageSelected != null) { 72 | mImageView.setImageDrawable(selected ? mSrcImageSelected : mSrcImage); 73 | } 74 | super.setSelected(selected); 75 | } 76 | } 77 | 78 | public boolean getSelected() { 79 | return mSelected; 80 | } 81 | 82 | @Override 83 | public void setOnTouchListener(OnTouchListener l) { 84 | mTouchListener = l; 85 | } 86 | 87 | @Override 88 | public void setOnClickListener(OnClickListener l) { 89 | mClickListener = l; 90 | } 91 | 92 | @Override 93 | public void onClick(View v) { 94 | if (mClickListener != null) { 95 | mClickListener.onClick(v); 96 | } 97 | } 98 | 99 | @Override 100 | public boolean onTouch(View v, MotionEvent event) { 101 | boolean flag = false; 102 | if (mTouchListener != null) { 103 | flag = mTouchListener.onTouch(v, event); 104 | } 105 | switch (event.getAction()) { 106 | case MotionEvent.ACTION_DOWN: 107 | mImageView.setAlpha(DOWN_ALPHA); 108 | return true; 109 | case MotionEvent.ACTION_HOVER_EXIT: 110 | case MotionEvent.ACTION_UP: 111 | mImageView.setAlpha(NORMAL_ALPHA); 112 | setSelected(!mSelected); 113 | onClick(v); 114 | return true; 115 | case MotionEvent.ACTION_HOVER_ENTER: 116 | mImageView.setAlpha(HOVER_ALPHA); 117 | return true; 118 | default: 119 | break; 120 | } 121 | return flag; 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /app/src/main/java/com/onscripter/plus/ListPreferencePlus.java: -------------------------------------------------------------------------------- 1 | package com.onscripter.plus; 2 | 3 | import android.content.Context; 4 | import android.preference.ListPreference; 5 | import android.util.AttributeSet; 6 | 7 | public class ListPreferencePlus extends ListPreference { 8 | public ListPreferencePlus(Context context) { 9 | super(context); 10 | } 11 | public ListPreferencePlus(Context context, AttributeSet attrs) { 12 | super(context, attrs); 13 | } 14 | 15 | @Override 16 | public void setValue(String value) { 17 | super.setValue(value); 18 | setSummary(getEntry()); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/onscripter/plus/ProgressDialogAsyncTask.java: -------------------------------------------------------------------------------- 1 | package com.onscripter.plus; 2 | 3 | import android.app.ProgressDialog; 4 | import android.content.Context; 5 | import android.content.DialogInterface; 6 | import android.content.DialogInterface.OnCancelListener; 7 | import android.os.AsyncTask; 8 | 9 | public abstract class ProgressDialogAsyncTask extends 10 | AsyncTask implements OnCancelListener { 11 | private static final String DEFAULT_MESSAGE = "Working..."; 12 | 13 | private ProgressDialog mProgressDial; 14 | private String mMessage; 15 | private final Context mCtx; 16 | private boolean mCancelable; 17 | private boolean mShowDialog; 18 | 19 | public ProgressDialogAsyncTask(Context ctx) { 20 | this(ctx, DEFAULT_MESSAGE, true); 21 | } 22 | 23 | public ProgressDialogAsyncTask(Context ctx, String message) { 24 | this(ctx, message, true); 25 | } 26 | 27 | public ProgressDialogAsyncTask(Context ctx, String message, boolean showDialog) { 28 | mCtx = ctx; 29 | mCancelable = true; 30 | setMessage(message); 31 | mShowDialog = showDialog; 32 | } 33 | 34 | public void setMessage(String message) { 35 | mMessage = message; 36 | if (mProgressDial != null) { 37 | mProgressDial.setMessage(mMessage); 38 | } 39 | } 40 | 41 | public String getMessage() { 42 | return mMessage; 43 | } 44 | 45 | public void show() { 46 | mShowDialog = true; 47 | mProgressDial = ProgressDialog.show(mCtx, "", mMessage, true, mCancelable, this); 48 | } 49 | 50 | public void setCancelable(boolean cancelable) { 51 | mCancelable = cancelable; 52 | } 53 | 54 | @Override 55 | protected void onPreExecute() { 56 | super.onPreExecute(); 57 | if (mShowDialog) { 58 | show(); 59 | } 60 | } 61 | 62 | @Override 63 | public void onCancel(DialogInterface dialog) { 64 | this.cancel(mCancelable); 65 | } 66 | 67 | public void dismiss() { 68 | if (mProgressDial != null && mProgressDial.isShowing()) { 69 | mProgressDial.dismiss(); 70 | mProgressDial = null; 71 | } 72 | } 73 | 74 | @Override 75 | protected void onPostExecute(Result result) { 76 | super.onPostExecute(result); 77 | dismiss(); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /app/src/main/java/com/onscripter/plus/Settings.java: -------------------------------------------------------------------------------- 1 | package com.onscripter.plus; 2 | 3 | import java.util.List; 4 | 5 | import android.content.Context; 6 | import android.content.pm.PackageInfo; 7 | import android.content.pm.PackageManager.NameNotFoundException; 8 | import android.content.res.Configuration; 9 | import android.content.res.Resources.Theme; 10 | import android.os.Bundle; 11 | import android.preference.Preference; 12 | import android.preference.Preference.OnPreferenceClickListener; 13 | import android.preference.PreferenceActivity; 14 | import android.preference.PreferenceManager; 15 | import android.view.MenuItem; 16 | import android.view.View; 17 | import android.widget.TextView; 18 | 19 | import com.onscripter.plus.settings.AboutSettingsFragment; 20 | import com.onscripter.plus.settings.GeneralSettingsFragment; 21 | import com.onscripter.plus.settings.LayoutPreference; 22 | import com.onscripter.plus.settings.LayoutPreference.OnLayoutViewCreatedListener; 23 | 24 | public final class Settings extends PreferenceActivity implements OnPreferenceClickListener { 25 | private ChangeLog mChangeLog; 26 | 27 | // TODO when removing 2.X dependency, put the fragment classes back 28 | private static String[] ValidFragments; 29 | 30 | public static void setVersionString(View layoutView, Context ctx) { 31 | PackageInfo pInfo; 32 | try { 33 | pInfo = ctx.getPackageManager().getPackageInfo(ctx.getPackageName(), 0); 34 | String version = pInfo.versionName; 35 | ((TextView)layoutView.findViewById(R.id.version_text)).setText(version); 36 | } catch (NameNotFoundException e) { 37 | e.printStackTrace(); 38 | } 39 | } 40 | 41 | @Override 42 | protected void onApplyThemeResource(Theme theme, int resid, boolean first) { 43 | // Set the theme 44 | String defaultThemeName = getString(R.string.settings_theme_default_value); 45 | String themeName = PreferenceManager.getDefaultSharedPreferences(this).getString( 46 | getString(R.string.settings_theme_key), defaultThemeName); 47 | int id = themeName.equals(defaultThemeName) ? R.style.Theme_Light : R.style.Theme_Dark; 48 | super.onApplyThemeResource(theme, id, first); 49 | } 50 | 51 | @SuppressWarnings("deprecation") 52 | @Override 53 | protected void onCreate(Bundle savedInstanceState) { 54 | if (ValidFragments == null) { 55 | ValidFragments = new String[]{ 56 | GeneralSettingsFragment.class.getName(), 57 | AboutSettingsFragment.class.getName() 58 | }; 59 | } 60 | super.onCreate(savedInstanceState); 61 | getActionBar().setDisplayHomeAsUpEnabled(true); 62 | getActionBar().setTitle(R.string.menu_action_settings); 63 | 64 | if (!isLargeTablet()) { 65 | // Old way of setting preferences for smaller devices 66 | addPreferencesFromResource(R.xml.general_settings); 67 | addPreferencesFromResource(R.xml.about_settings); 68 | 69 | Preference preference = getPreferenceScreen().findPreference(getString(R.string.settings_about_change_log_key)); 70 | preference.setOnPreferenceClickListener(this); 71 | 72 | // Put the version number inside the app about preference screen 73 | LayoutPreference appAboutPref = (LayoutPreference)findPreference(getString(R.string.settings_about_app_key)); 74 | appAboutPref.setOnLayoutViewCreatedListener(new OnLayoutViewCreatedListener() { 75 | @Override 76 | public void onLayoutViewCreated(View layoutView) { 77 | setVersionString(layoutView, Settings.this); 78 | } 79 | }); 80 | } 81 | } 82 | 83 | @Override 84 | public void onBuildHeaders(List
target) { 85 | if (isLargeTablet()) { 86 | loadHeadersFromResource(R.xml.settings_header, target); 87 | } 88 | } 89 | 90 | @Override 91 | protected boolean isValidFragment(String fragmentName) { 92 | for (String name: ValidFragments) { 93 | if (fragmentName.equals(name)) { 94 | return true; 95 | } 96 | } 97 | return false; 98 | } 99 | 100 | @Override 101 | public boolean onPreferenceClick(Preference preference) { 102 | if (mChangeLog == null) { 103 | mChangeLog = new ChangeLog(this); 104 | } 105 | mChangeLog.show(); 106 | return false; 107 | } 108 | 109 | @Override 110 | public boolean onOptionsItemSelected(MenuItem item) { 111 | switch (item.getItemId()) { 112 | case android.R.id.home: 113 | finish(); 114 | break; 115 | } 116 | return true; 117 | } 118 | 119 | private boolean isLargeTablet() { 120 | return (getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) 121 | >= Configuration.SCREENLAYOUT_SIZE_XLARGE; 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /app/src/main/java/com/onscripter/plus/UnicodeUtil.java: -------------------------------------------------------------------------------- 1 | package com.onscripter.plus; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.BufferedWriter; 5 | import java.io.ByteArrayInputStream; 6 | import java.io.ByteArrayOutputStream; 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import java.io.InputStreamReader; 10 | import java.io.OutputStreamWriter; 11 | import java.io.PushbackInputStream; 12 | import java.io.UnsupportedEncodingException; 13 | import java.io.Writer; 14 | 15 | public class UnicodeUtil { 16 | 17 | public static byte[] convert(byte[] bytes, String encout) throws Exception { 18 | // Workaround for bug that will not be fixed by SUN 19 | // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058 20 | UnicodeInputStream uis = new UnicodeInputStream( 21 | new ByteArrayInputStream(bytes), "ASCII"); 22 | boolean unicodeOutputReqd = (getBOM(encout) != null) ? true : false; 23 | String enc = uis.getEncoding(); 24 | String BOM = getBOM(enc); // get the BOM of the inputstream 25 | 26 | if (BOM == null) { 27 | // inputstream looks like ascii... 28 | // create a BOM based on the outputstream 29 | BOM = getBOM(encout); 30 | } 31 | uis.close(); 32 | 33 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 34 | BufferedReader br = new BufferedReader(new InputStreamReader( 35 | new ByteArrayInputStream(bytes, uis.getBOMOffset(), 36 | bytes.length), enc)); 37 | Writer w = new BufferedWriter(new OutputStreamWriter(out, encout)); 38 | 39 | // dont write a BOM for ascii(out) as the OutputStreamWriter 40 | // will not process it correctly. 41 | if (BOM != null && unicodeOutputReqd) { 42 | w.write(BOM); 43 | } 44 | 45 | char[] buffer = new char[4096]; 46 | int len; 47 | while ((len = br.read(buffer)) != -1) { 48 | w.write(buffer, 0, len); 49 | } 50 | 51 | br.close(); // Close the input. 52 | w.close(); // Flush and close output. 53 | return out.toByteArray(); 54 | } 55 | 56 | public static String getBOM(String enc) throws UnsupportedEncodingException { 57 | if ("UTF-8".equals(enc)) { 58 | byte[] bom = new byte[3]; 59 | bom[0] = (byte) 0xEF; 60 | bom[1] = (byte) 0xBB; 61 | bom[2] = (byte) 0xBF; 62 | return new String(bom, enc); 63 | } else if ("UTF-16BE".equals(enc)) { 64 | byte[] bom = new byte[2]; 65 | bom[0] = (byte) 0xFE; 66 | bom[1] = (byte) 0xFF; 67 | return new String(bom, enc); 68 | } else if ("UTF-16LE".equals(enc)) { 69 | byte[] bom = new byte[2]; 70 | bom[0] = (byte) 0xFF; 71 | bom[1] = (byte) 0xFE; 72 | return new String(bom, enc); 73 | } else if ("UTF-32BE".equals(enc)) { 74 | byte[] bom = new byte[4]; 75 | bom[0] = (byte) 0x00; 76 | bom[1] = (byte) 0x00; 77 | bom[2] = (byte) 0xFE; 78 | bom[3] = (byte) 0xFF; 79 | return new String(bom, enc); 80 | } else if ("UTF-32LE".equals(enc)) { 81 | byte[] bom = new byte[4]; 82 | bom[0] = (byte) 0x00; 83 | bom[1] = (byte) 0x00; 84 | bom[2] = (byte) 0xFF; 85 | bom[3] = (byte) 0xFE; 86 | return new String(bom, enc); 87 | } else { 88 | return null; 89 | } 90 | 91 | } 92 | 93 | public static class UnicodeInputStream extends InputStream { 94 | private final PushbackInputStream internalIn; 95 | 96 | private boolean isInited = false; 97 | 98 | private int BOMOffset = -1; 99 | 100 | private final String defaultEnc; 101 | 102 | private String encoding; 103 | 104 | public static final int BOM_SIZE = 4; 105 | 106 | public UnicodeInputStream(InputStream in, String defaultEnc) { 107 | internalIn = new PushbackInputStream(in, BOM_SIZE); 108 | this.defaultEnc = defaultEnc; 109 | } 110 | 111 | public String getDefaultEncoding() { 112 | return defaultEnc; 113 | } 114 | 115 | public String getEncoding() { 116 | if (!isInited) { 117 | try { 118 | init(); 119 | } catch (IOException ex) { 120 | IllegalStateException ise = new IllegalStateException( 121 | "Init method failed."); 122 | ise.initCause(ise); 123 | throw ise; 124 | } 125 | } 126 | return encoding; 127 | } 128 | 129 | /** 130 | * Read-ahead four bytes and check for BOM marks. Extra bytes are unread 131 | * back to the stream, only BOM bytes are skipped. 132 | */ 133 | protected void init() throws IOException { 134 | if (isInited) 135 | return; 136 | 137 | byte bom[] = new byte[BOM_SIZE]; 138 | int n, unread; 139 | n = internalIn.read(bom, 0, bom.length); 140 | 141 | if ((bom[0] == (byte) 0x00) && (bom[1] == (byte) 0x00) 142 | && (bom[2] == (byte) 0xFE) && (bom[3] == (byte) 0xFF)) { 143 | encoding = "UTF-32BE"; 144 | unread = n - 4; 145 | } else if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE) 146 | && (bom[2] == (byte) 0x00) && (bom[3] == (byte) 0x00)) { 147 | encoding = "UTF-32LE"; 148 | unread = n - 4; 149 | } else if ((bom[0] == (byte) 0xEF) && (bom[1] == (byte) 0xBB) 150 | && (bom[2] == (byte) 0xBF)) { 151 | encoding = "UTF-8"; 152 | unread = n - 3; 153 | } else if ((bom[0] == (byte) 0xFE) && (bom[1] == (byte) 0xFF)) { 154 | encoding = "UTF-16BE"; 155 | unread = n - 2; 156 | } else if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE)) { 157 | encoding = "UTF-16LE"; 158 | unread = n - 2; 159 | } else { 160 | // Unicode BOM mark not found, unread all bytes 161 | encoding = defaultEnc; 162 | unread = n; 163 | } 164 | BOMOffset = BOM_SIZE - unread; 165 | if (unread > 0) 166 | internalIn.unread(bom, (n - unread), unread); 167 | 168 | isInited = true; 169 | } 170 | 171 | @Override 172 | public void close() throws IOException { 173 | // init(); 174 | isInited = true; 175 | internalIn.close(); 176 | } 177 | 178 | @Override 179 | public int read() throws IOException { 180 | // init(); 181 | isInited = true; 182 | return internalIn.read(); 183 | } 184 | 185 | public int getBOMOffset() { 186 | return BOMOffset; 187 | } 188 | } 189 | 190 | } -------------------------------------------------------------------------------- /app/src/main/java/com/onscripter/plus/ViewAdapterBase.java: -------------------------------------------------------------------------------- 1 | package com.onscripter.plus; 2 | 3 | import java.util.ArrayList; 4 | 5 | import android.content.Context; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.ArrayAdapter; 10 | 11 | 12 | public abstract class ViewAdapterBase extends ArrayAdapter{ 13 | protected ArrayList entries; 14 | private final Context context; 15 | private final int widgetLayout; 16 | private final int[] resources; 17 | 18 | public ViewAdapterBase(Context ctx, int widgetResourceLayout, int[] viewResourceIdListInWidget, ArrayList list) { 19 | super(ctx, 0, list); 20 | entries = list; 21 | context = ctx; 22 | resources = viewResourceIdListInWidget; 23 | widgetLayout = widgetResourceLayout; 24 | } 25 | 26 | protected abstract void setWidgetValues(int position, TItem item, View[] elements, View layout); 27 | 28 | public ArrayList getList() { 29 | return entries; 30 | } 31 | 32 | protected void onCreateListItem(int position, View item, ViewGroup parent) { 33 | } 34 | 35 | @Override 36 | public View getView(int position, View convertView, ViewGroup parent) { 37 | View viewObj = convertView; 38 | View[] elements = null; 39 | if (viewObj == null) { 40 | LayoutInflater inflator = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 41 | viewObj = inflator.inflate(widgetLayout, null); 42 | int size = resources.length; 43 | elements = new View[size]; 44 | for (int i = 0; i < size; i++) { 45 | elements[i] = viewObj.findViewById(resources[i]); 46 | } 47 | viewObj.setTag(elements); 48 | onCreateListItem(position, viewObj, parent); 49 | } else { 50 | elements = (View[]) viewObj.getTag(); 51 | } 52 | final TItem item = entries.get(position); 53 | for (View v: elements) { 54 | v.setVisibility(View.VISIBLE); 55 | } 56 | setWidgetValues(position, item, elements, viewObj); 57 | return viewObj; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/java/com/onscripter/plus/bugtracking/ModifyServerRequest.java: -------------------------------------------------------------------------------- 1 | package com.onscripter.plus.bugtracking; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.DataOutputStream; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.net.HttpURLConnection; 8 | import java.net.URL; 9 | import java.util.ArrayList; 10 | 11 | import org.json.JSONException; 12 | import org.json.JSONObject; 13 | 14 | import android.util.Pair; 15 | 16 | public class ModifyServerRequest { 17 | static enum METHOD { PUT, POST }; 18 | 19 | private HttpURLConnection mConnection; 20 | private ArrayList mFieldData; 21 | private ArrayList> mFileData; 22 | 23 | private final METHOD mMethod; 24 | 25 | /** 26 | * Default constructor that sets method to be POST 27 | */ 28 | public ModifyServerRequest() { 29 | mMethod = METHOD.POST; 30 | } 31 | 32 | /** 33 | * Constructor to specify the method to use, either 34 | * POST or PUT 35 | * @param method 36 | */ 37 | public ModifyServerRequest(METHOD method) { 38 | mMethod = method; 39 | } 40 | 41 | /** 42 | * Open the connection specifying the url 43 | * @param url 44 | * @throws IOException 45 | */ 46 | public void openConnection(String url) throws IOException { 47 | if (mConnection == null) { 48 | try { 49 | URL _url = new URL(url); 50 | System.setProperty("http.keepAlive", "false"); 51 | mConnection = (HttpURLConnection) _url.openConnection(); 52 | mConnection.setDoOutput(true); 53 | mConnection.setDoInput(true); 54 | mConnection.setUseCaches(false); 55 | mConnection.setRequestMethod(mMethod == METHOD.PUT ? "PUT" : "POST"); 56 | mConnection.setReadTimeout(10000); 57 | mFieldData = new ArrayList(); 58 | mFileData = new ArrayList>(); 59 | } catch (IOException e) { 60 | mConnection = null; 61 | throw e; 62 | } 63 | } 64 | } 65 | 66 | /** 67 | * Add a field to the POST/PUT as data to send to the server 68 | * @param field 69 | * @param value 70 | */ 71 | public void putField(String field, String value) { 72 | if (mFieldData != null) { 73 | mFieldData.add(field + "=" + value); 74 | } 75 | } 76 | 77 | /** 78 | * Add a file with its contents handled as binary to send to the server 79 | * @param field 80 | * @param data 81 | */ 82 | public void putFile(String field, byte[] data) { 83 | if (mFieldData != null) { 84 | mFileData.add(Pair.create(field + "|" + data.length + "=", data)); 85 | } 86 | } 87 | 88 | /** 89 | * Send the request to the server after specifying the fields and files 90 | * @throws IOException 91 | */ 92 | public void send() throws IOException { 93 | if (mConnection != null) { 94 | DataOutputStream writer = new DataOutputStream(mConnection.getOutputStream()); 95 | for (int i = 0; i < mFieldData.size(); i++) { 96 | writer.write(mFieldData.get(i).getBytes("UTF-8")); 97 | if (i + 1 < mFieldData.size()) { 98 | writer.writeBytes("&"); 99 | } 100 | } 101 | if (mFileData.size() > 0) { 102 | writer.writeBytes("&"); 103 | for (int i = 0; i < mFileData.size(); i++) { 104 | Pair data = mFileData.get(i); 105 | writer.writeBytes(data.first); 106 | writer.write(data.second); 107 | if (i + 1 < mFileData.size()) { 108 | writer.writeBytes("&"); 109 | } 110 | } 111 | } 112 | writer.flush(); 113 | writer.close(); 114 | mFileData.clear(); 115 | mFieldData.clear(); 116 | } 117 | } 118 | 119 | /** 120 | * Disconnects communication to the server. 121 | * You should run this whenever you use openConnection (place this 122 | * in the finally clause of a try-catch) 123 | */ 124 | public void disconnect() { 125 | if (mConnection != null) { 126 | mConnection.disconnect(); 127 | mConnection = null; 128 | } 129 | } 130 | 131 | /** 132 | * Retrieves the response code from the server. 133 | * e.g. Good = 200 134 | * @return 135 | * @throws IOException 136 | */ 137 | public int getResponseCode() throws IOException { 138 | return mConnection != null ? mConnection.getResponseCode() : 0; 139 | } 140 | 141 | /** 142 | * Retrieves the data that the server returns. If the response 143 | * code is 500 then this most likely will return null 144 | * @return 145 | * @throws IOException 146 | */ 147 | public String getResponse() throws IOException { 148 | StringBuilder sb = new StringBuilder(); 149 | BufferedReader br = null; 150 | try { 151 | br = new BufferedReader(new InputStreamReader(mConnection.getInputStream())); 152 | String line; 153 | while ((line = br.readLine()) != null) { 154 | sb.append(line + "\n"); 155 | } 156 | } finally { 157 | if (br != null) { 158 | br.close(); 159 | } 160 | } 161 | return sb.toString(); 162 | } 163 | 164 | /** 165 | * Returns the response data as a JSON. You must know if the server can 166 | * return JSON files otherwise, this will throw an exception. 167 | * @return 168 | * @throws IOException 169 | * @throws JSONException 170 | */ 171 | public JSONObject getResponseJSON() throws IOException, JSONException { 172 | return new JSONObject(getResponse()); 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /app/src/main/java/com/onscripter/plus/bugtracking/TracedONScripterView.java: -------------------------------------------------------------------------------- 1 | package com.onscripter.plus.bugtracking; 2 | 3 | import java.io.File; 4 | 5 | import android.app.Activity; 6 | import android.content.pm.ApplicationInfo; 7 | import android.os.Environment; 8 | 9 | import com.onscripter.ONScripterView; 10 | 11 | public class TracedONScripterView extends ONScripterView { 12 | 13 | private ONScripterTracer.Playback mPlayback; 14 | final String rootFolder; 15 | final String mCurrentDirectory; 16 | 17 | public TracedONScripterView(Activity context, String currentDirectory, 18 | String fontPath, String savePath, boolean useHQAudio, 19 | boolean shouldRenderOutline) { 20 | super(context, currentDirectory, fontPath, savePath, useHQAudio, shouldRenderOutline); 21 | 22 | mCurrentDirectory = currentDirectory; 23 | rootFolder = savePath != null ? savePath : currentDirectory; 24 | 25 | // String traceFile = getContext().getApplicationContext().getFilesDir() + "/" + ONScripterTracer.TRACE_FILE_NAME; 26 | String traceFile = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) 27 | + "/" + ONScripterTracer.TRACE_FILE_NAME; 28 | if (isDebug() && ONScripterTracer.playbackEnabled() && new File(traceFile).exists()) { 29 | mPlayback = new ONScripterTracer.Playback(this, traceFile); 30 | mPlayback.start(); 31 | } else { 32 | ONScripterTracer.init(context); 33 | ONScripterTracer.open(false); 34 | } 35 | } 36 | 37 | @Override 38 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 39 | int parentWidth = MeasureSpec.getSize(widthMeasureSpec); 40 | int parentHeight = MeasureSpec.getSize(heightMeasureSpec); 41 | ONScripterTracer.traceViewDimensions(parentWidth, parentHeight); 42 | this.setMeasuredDimension(parentWidth, parentHeight); 43 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 44 | } 45 | 46 | @Override 47 | public void receiveException(String message, String currentLineBuffer, String backtrace) { 48 | super.receiveException(message, currentLineBuffer, backtrace); 49 | if (mPlayback != null) { 50 | mPlayback.stop(); 51 | mPlayback = null; 52 | } else { 53 | ONScripterTracer.traceCrash(); 54 | ONScripterTracer.close(); 55 | ONScripterTracer.open(); 56 | } 57 | } 58 | 59 | @Override 60 | public void exitApp() { 61 | if (mPlayback != null) { 62 | mPlayback.stop(); 63 | mPlayback = null; 64 | } else { 65 | ONScripterTracer.close(); 66 | } 67 | super.exitApp(); 68 | } 69 | 70 | @Override 71 | public void onPause() { 72 | super.onPause(); 73 | if (mPlayback != null) { 74 | mPlayback.stop(); 75 | mPlayback = null; 76 | } else { 77 | ONScripterTracer.close(); 78 | } 79 | } 80 | 81 | @Override 82 | public void onResume() { 83 | if (mPlayback == null) { 84 | ONScripterTracer.open(); 85 | } 86 | super.onResume(); 87 | } 88 | 89 | @Override 90 | protected void nativeKey(int keyCode, int down) { 91 | if (mPlayback == null) { 92 | ONScripterTracer.traceKeyEvent(keyCode, down); 93 | } 94 | super.nativeKey(keyCode, down); 95 | } 96 | 97 | @Override 98 | protected void nativeMouse(int x, int y, int action) { 99 | if (mPlayback == null) { 100 | ONScripterTracer.traceMouseEvent(x, y, action); 101 | } 102 | super.nativeMouse(x, y, action); 103 | } 104 | 105 | @Override 106 | public void playVideo(char[] filename, boolean clickToSkip, boolean shouldLoop) { 107 | if (allowVideo()) { 108 | File video = new File(mCurrentDirectory + "/" + new String(filename).replace("\\", "/")); 109 | if (video.exists() && video.canRead()) { 110 | ONScripterTracer.traceVideoStartEvent(); 111 | } 112 | super.playVideo(filename, clickToSkip, shouldLoop); 113 | } 114 | } 115 | 116 | /** 117 | * Always skip videos when playing back traces 118 | * @return 119 | */ 120 | protected boolean allowVideo() { 121 | return mPlayback == null; 122 | } 123 | 124 | void triggerMouseEvent(int x, int y, int action) { 125 | nativeMouse( x, y, action ); 126 | } 127 | 128 | void triggerKeyEvent(int keyCode, int down) { 129 | nativeKey( keyCode, down ); 130 | } 131 | 132 | protected boolean isDebug() { 133 | return (getContext().getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; 134 | } 135 | 136 | protected void onLoadFile(String filename, String savePath) { 137 | if (mPlayback == null) { 138 | String path = rootFolder + "/" + (savePath == null ? "" : (savePath + "/")) + filename; 139 | ONScripterTracer.traceLoadEvent(getContext(), path, savePath); 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /app/src/main/java/com/onscripter/plus/settings/AboutSettingsFragment.java: -------------------------------------------------------------------------------- 1 | package com.onscripter.plus.settings; 2 | 3 | import android.os.Bundle; 4 | import android.preference.Preference; 5 | import android.preference.Preference.OnPreferenceClickListener; 6 | import android.preference.PreferenceFragment; 7 | import android.util.TypedValue; 8 | import android.view.View; 9 | 10 | import com.onscripter.plus.ChangeLog; 11 | import com.onscripter.plus.R; 12 | import com.onscripter.plus.Settings; 13 | import com.onscripter.plus.settings.LayoutPreference.OnLayoutViewCreatedListener; 14 | 15 | public class AboutSettingsFragment extends PreferenceFragment implements OnPreferenceClickListener { 16 | private ChangeLog mChangeLog; 17 | 18 | @Override 19 | public void onCreate(Bundle savedInstanceState) { 20 | super.onCreate(savedInstanceState); 21 | addPreferencesFromResource(R.xml.about_settings); 22 | findPreference(getString(R.string.settings_about_change_log_key)) 23 | .setOnPreferenceClickListener(this); 24 | 25 | // Set the corrected padding on the left to follow the same indent as the rest and set version number 26 | LayoutPreference p = (LayoutPreference) findPreference(getString(R.string.settings_about_app_key)); 27 | p.setOnLayoutViewCreatedListener(new OnLayoutViewCreatedListener() { 28 | @Override 29 | public void onLayoutViewCreated(View layoutView) { 30 | int paddingLeft = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 31 | getResources().getDimension(R.dimen.preference_padding_start), 32 | getResources().getDisplayMetrics()); 33 | layoutView.setPadding(paddingLeft, 0, 0, 0); 34 | Settings.setVersionString(layoutView, getActivity()); 35 | } 36 | }); 37 | } 38 | 39 | @Override 40 | public boolean onPreferenceClick(Preference preference) { 41 | if (mChangeLog == null) { 42 | mChangeLog = new ChangeLog(getActivity()); 43 | } 44 | mChangeLog.show(); 45 | return false; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/onscripter/plus/settings/GeneralSettingsFragment.java: -------------------------------------------------------------------------------- 1 | package com.onscripter.plus.settings; 2 | 3 | import android.os.Bundle; 4 | import android.preference.PreferenceFragment; 5 | 6 | import com.onscripter.plus.R; 7 | 8 | public class GeneralSettingsFragment extends PreferenceFragment { 9 | @Override 10 | public void onCreate(Bundle savedInstanceState) { 11 | super.onCreate(savedInstanceState); 12 | addPreferencesFromResource(R.xml.general_settings); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/onscripter/plus/settings/LayoutPreference.java: -------------------------------------------------------------------------------- 1 | package com.onscripter.plus.settings; 2 | 3 | import android.content.Context; 4 | import android.preference.Preference; 5 | import android.util.AttributeSet; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | 10 | public class LayoutPreference extends Preference { 11 | private View mLayoutView; 12 | private OnLayoutViewCreatedListener mListener; 13 | 14 | public interface OnLayoutViewCreatedListener { 15 | public void onLayoutViewCreated(View layoutView); 16 | } 17 | 18 | public LayoutPreference(Context context, AttributeSet attrs) { 19 | super(context, attrs); 20 | } 21 | 22 | @Override 23 | protected View onCreateView(ViewGroup parent) { 24 | final LayoutInflater layoutInflater = 25 | (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 26 | mLayoutView = layoutInflater.inflate(getLayoutResource(), parent, false); 27 | if (mListener != null) { 28 | mListener.onLayoutViewCreated(mLayoutView); 29 | } 30 | return mLayoutView; 31 | } 32 | 33 | public void setOnLayoutViewCreatedListener(OnLayoutViewCreatedListener listener) { 34 | mListener = listener; 35 | } 36 | 37 | public View getLayoutView() { 38 | return mLayoutView; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/jrummy/sdfix/Remounter.java: -------------------------------------------------------------------------------- 1 | package jrummy.sdfix; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileReader; 6 | import java.io.IOException; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | import android.text.TextUtils; 11 | import android.util.Log; 12 | 13 | /** 14 | * 15 | * @author Jared Rummler 16 | * 17 | */ 18 | public class Remounter { 19 | 20 | private static final String TAG = Remounter.class.getName(); 21 | /** /proc/mounts File */ 22 | public static final File PROC_MOUNTS = new File("/proc/mounts"); 23 | /** Value of ANDROID_ROOT environmental variable or /system if empty */ 24 | public static final String ANDROID_ROOT = System.getenv("ANDROID_ROOT"); 25 | /** Read/Write "rw" */ 26 | public static final String RW = "rw"; 27 | /** Read-only "ro" */ 28 | public static final String RO = "ro"; 29 | 30 | /** 31 | * Contains info extracted from a line in /proc/mounts 32 | */ 33 | public static class Mount { 34 | /** The line in /proc/mounts */ 35 | public String line; 36 | public String device; 37 | public String mountpoint; 38 | public String type; 39 | public String options; 40 | public String mountOption; 41 | 42 | /** 43 | * 44 | * @param line A line in /proc/mounts 45 | * @throws IndexOutOfBoundsException 46 | * @throws NullPointerException 47 | */ 48 | public Mount(String line) throws IndexOutOfBoundsException, NullPointerException { 49 | final String[] arr = line.split("\\s+"); 50 | this.line = line; 51 | this.device = arr[0]; 52 | this.mountpoint = arr[1]; 53 | this.type = arr[2]; 54 | this.options = arr[3]; 55 | this.mountOption = this.options.split(",")[0]; 56 | } 57 | 58 | /** 59 | * @return true if the filesystem is mounted read-only. 60 | */ 61 | public boolean isMountedReadOnly() { 62 | if (this.mountOption != null) { 63 | return this.mountOption.equals(RO); 64 | } 65 | return false; 66 | } 67 | 68 | /** 69 | * @return true if the filesystem is mounted read/write. 70 | */ 71 | public boolean isMountedReadWrite() { 72 | if (this.mountOption != null) { 73 | return this.mountOption.equals(RW); 74 | } 75 | return false; 76 | } 77 | 78 | /** 79 | * @return The command used to remount the filesystem read/write. 80 | */ 81 | public String getMountCommand() { 82 | return getMountCommand(RW); 83 | } 84 | 85 | /** 86 | * 87 | * @param mountType "ro" or "rw" 88 | * @return The command used to remount the filesystem read/write or read-only 89 | */ 90 | public String getMountCommand(String mountType) { 91 | return String.format("mount -o remount,%s %s %s", 92 | mountType, this.device, this.mountpoint); 93 | } 94 | 95 | private void setMountOption(String type) { 96 | this.line.replaceAll(this.mountOption + ",", type + ","); 97 | this.options.replaceAll(this.mountOption + ",", type + ","); 98 | this.mountOption = type; 99 | } 100 | 101 | /** 102 | * Mounts a filesystem read-only or read/write 103 | * @param mountType "ro" or "rw" 104 | * @return true if successful 105 | */ 106 | public boolean remount(String mountType) { 107 | String command = getMountCommand(mountType); 108 | if (Shell.SU.run(command).success()) { 109 | setMountOption(mountType); 110 | return true; 111 | } 112 | 113 | command = "busybox " + command; 114 | if (Shell.SU.run(command).success()) { 115 | setMountOption(mountType); 116 | return true; 117 | } 118 | 119 | return false; 120 | } 121 | 122 | /** 123 | * Mounts a filesystem read/write 124 | * @return true if successful 125 | */ 126 | public boolean remountReadWrite() { 127 | return remount(RW); 128 | } 129 | 130 | /** 131 | * Mounts a filesystem read-only 132 | * @return true if successful 133 | */ 134 | public boolean remountReadOnly() { 135 | return remount(RO); 136 | } 137 | } 138 | 139 | /** 140 | * Parses /proc/mounts and returns a List of {@link Remounter.Mount} 141 | * @return 142 | */ 143 | public static List getMounts() { 144 | final List mounts = new ArrayList(); 145 | if (PROC_MOUNTS.canRead()) { 146 | try { 147 | final BufferedReader br = new BufferedReader(new FileReader(PROC_MOUNTS)); 148 | try { 149 | String line = null; 150 | while ((line = br.readLine()) != null) { 151 | try { 152 | mounts.add(new Mount(line)); 153 | } catch (Exception ignore) { } 154 | } 155 | } finally { 156 | br.close(); 157 | } 158 | if (!mounts.isEmpty()) { 159 | return mounts; 160 | } 161 | } catch (IOException e) { 162 | Log.e(TAG, "Failed reading " + PROC_MOUNTS, e); 163 | mounts.clear(); 164 | } 165 | } 166 | 167 | final String command = "cat \"" + PROC_MOUNTS + "\""; 168 | final Shell.CommandResult r = Shell.SU.run(command); 169 | if (r.success() && !TextUtils.isEmpty(r.stdout)) { 170 | final String[] lines = r.stdout.split("\n"); 171 | for (final String line : lines) { 172 | try { 173 | mounts.add(new Mount(line)); 174 | } catch (Exception ignore) { } 175 | } 176 | } 177 | 178 | return mounts; 179 | } 180 | 181 | /** 182 | * 183 | * @param file 184 | * @return The filesystem in /proc/mounts for this file or null. 185 | */ 186 | public static Mount getMount(File file) { 187 | return getMount(file.getAbsolutePath()); 188 | } 189 | 190 | /** 191 | * 192 | * @param path 193 | * @return The filesystem in /proc/mounts for this file or null. 194 | */ 195 | public static Mount getMount(String path) { 196 | final List mounts = getMounts(); 197 | if (mounts.isEmpty()) { 198 | return null; 199 | } 200 | 201 | while (path != null) { 202 | for (final Mount mount : mounts) { 203 | if (mount.mountpoint.equals(path)) { 204 | return mount; 205 | } 206 | } 207 | 208 | if (path.equals(File.separator)) { 209 | return null; 210 | } 211 | 212 | path = new File(path).getParent(); 213 | if (path == null) { 214 | path = File.separator; 215 | } 216 | } 217 | 218 | return null; 219 | } 220 | 221 | /** 222 | * Remounts a filesystem read/write or read-only 223 | * @param path Path to the file 224 | * @param type "rw" or "ro" 225 | * @return true if successful 226 | */ 227 | public static boolean remount(String path, String type) { 228 | final Mount mount = getMount(path); 229 | if (mount == null) { 230 | Log.i(TAG, "Failed finding mountpoint for " + path); 231 | return false; 232 | } 233 | 234 | if (mount.mountOption.equals(type)) { 235 | // Already mounted 236 | return true; 237 | } 238 | 239 | return mount.remount(type); 240 | } 241 | 242 | /** @see #remount(String, String) */ 243 | public static boolean remount(File file, String type) { 244 | return remount(file.getAbsolutePath(), type); 245 | } 246 | 247 | /** @see #remount(String, String) */ 248 | public static boolean rw(String path) { 249 | return remount(path, RW); 250 | } 251 | 252 | /** @see #remount(String, String) */ 253 | public static boolean ro(String path) { 254 | return remount(path, RO); 255 | } 256 | 257 | /** @see #remount(String, String) */ 258 | public static boolean rw(File file) { 259 | return remount(file, RW); 260 | } 261 | 262 | /** @see #remount(String, String) */ 263 | public static boolean ro(File file) { 264 | return remount(file, RO); 265 | } 266 | 267 | /** @see #remount(String, String) */ 268 | public static boolean mountSystemRw() { 269 | return rw(ANDROID_ROOT); 270 | } 271 | 272 | /** @see #remount(String, String) */ 273 | public static boolean mountSystemRo() { 274 | return ro(ANDROID_ROOT); 275 | } 276 | } 277 | -------------------------------------------------------------------------------- /app/src/main/java/jrummy/sdfix/SDFix.java: -------------------------------------------------------------------------------- 1 | package jrummy.sdfix; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.BufferedWriter; 5 | import java.io.File; 6 | import java.io.FileNotFoundException; 7 | import java.io.FileReader; 8 | import java.io.FileWriter; 9 | import java.io.IOException; 10 | 11 | import android.content.Context; 12 | import android.util.Log; 13 | 14 | public class SDFix { 15 | 16 | private static final String TAG = SDFix.class.getName(); 17 | 18 | public static final String PLATFORM_XML = "/system/etc/permissions/platform.xml"; 19 | 20 | /* Modified: Matthew Ng; the name is modified because it does not truly say if writable, for example 21 | * the fix is completed but user has not restarted device yet. 22 | */ 23 | public static boolean isRemovableStorageWritableFixApplied() throws IOException, FileNotFoundException { 24 | boolean isRemovableStorageWritable = false; 25 | final BufferedReader reader = new BufferedReader(new FileReader(PLATFORM_XML)); 26 | boolean isPermissionLine = false; 27 | String line = reader.readLine(); 28 | while (line != null) { 29 | if (line.contains("android.permission.WRITE_EXTERNAL_STORAGE")) { 30 | isPermissionLine = true; 31 | } 32 | else if (isPermissionLine) { 33 | if (line.contains("")) { 34 | isPermissionLine = false; 35 | } 36 | else if (line.contains("media_rw")) { 37 | isRemovableStorageWritable = true; 38 | } 39 | } 40 | line = reader.readLine(); 41 | } 42 | reader.close(); 43 | return isRemovableStorageWritable; 44 | } 45 | 46 | public static String getModifiedPlatformXml() throws IOException, FileNotFoundException { 47 | final StringBuilder sb = new StringBuilder(); 48 | final BufferedReader reader = new BufferedReader(new FileReader(PLATFORM_XML)); 49 | boolean addLine = false; 50 | String line = reader.readLine(); 51 | while (line != null) { 52 | if (line.contains("android.permission.WRITE_EXTERNAL_STORAGE")) { 53 | addLine = true; 54 | } 55 | else if (addLine) { 56 | if (line.contains("")) { 57 | sb.append(" "); 58 | sb.append('\n'); 59 | addLine = false; 60 | } 61 | } 62 | sb.append(line); 63 | sb.append('\n'); 64 | line = reader.readLine(); 65 | } 66 | reader.close(); 67 | return sb.toString(); 68 | } 69 | 70 | public static boolean writeModifiedPlatformXml(File outfile) throws IOException { 71 | String text = ""; 72 | try { 73 | text = getModifiedPlatformXml(); 74 | } catch (Exception e) { 75 | return false; 76 | } 77 | final BufferedWriter writer = new BufferedWriter(new FileWriter(outfile)); 78 | writer.append(text); 79 | writer.close(); 80 | return true; 81 | } 82 | 83 | public static boolean fixPermissions(Context context) throws FileNotFoundException, IOException { 84 | if (isRemovableStorageWritableFixApplied()) { 85 | Log.i(TAG, PLATFORM_XML + " is already modified to allow apps to write to a removable SD card"); 86 | return true; 87 | } 88 | 89 | final File outfile = new File(context.getFilesDir(), "platform.xml"); 90 | try { 91 | if (!writeModifiedPlatformXml(outfile)) { 92 | return false; 93 | } 94 | } catch (Exception e) { 95 | Log.e(TAG, "Failed to write the modified file to " + outfile, e); 96 | return false; 97 | } 98 | 99 | if (!Remounter.mountSystemRw()) { 100 | Log.i(TAG, "Failed to mount system read/write"); 101 | return false; 102 | } 103 | 104 | String[] commands = { 105 | "cp " + PLATFORM_XML + " /system/etc/permissions/platform.xml.bak", 106 | "cp \"" + outfile + "\" \"" + PLATFORM_XML + "\"", 107 | "chmod 0644 " + PLATFORM_XML, 108 | "chmod 0644 /system/etc/permissions/platform.xml.bak" 109 | }; 110 | 111 | if (!Shell.SU.run(commands).success()) { 112 | Log.i(TAG, "Failed to copy over " + outfile + " to " + PLATFORM_XML); 113 | return false; 114 | } 115 | 116 | Remounter.mountSystemRo(); 117 | 118 | return true; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /app/src/main/java/jrummy/sdfix/Shell.java: -------------------------------------------------------------------------------- 1 | package jrummy.sdfix; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.DataOutputStream; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.util.List; 8 | 9 | import android.os.Handler; 10 | import android.text.TextUtils; 11 | import android.util.Log; 12 | 13 | /** 14 | * Shell.java runs commands as if in a native shell instance, and can 15 | * return stdout, stderr, and exit code.

16 | * 17 | * Example usage:
18 | * new Shell("sh").run("ls"); 19 | * 20 | * @author Jared Rummler 21 | * 22 | */ 23 | public class Shell { 24 | 25 | private static final String TAG = "Shell"; 26 | 27 | /** The LD_LIBRARY_PATH environmental variable value **/ 28 | private static final String LD_LIBRARY_PATH = System.getenv("LD_LIBRARY_PATH"); 29 | 30 | private static Boolean canSu; 31 | private String shell; 32 | 33 | private Handler mHandler; 34 | private CommandListener mListener; 35 | 36 | public interface CommandListener { 37 | public void onExecuteCommand(String command); 38 | public void onReadOutput(String line, boolean stdout); 39 | public void onFinished(CommandResult result); 40 | } 41 | 42 | /** 43 | * Constructor to create a new shell to run linux commands in. 44 | * 45 | * @param shell The name of the shell commands will be executed in 46 | */ 47 | public Shell(String shell) { 48 | this.shell = shell; 49 | } 50 | 51 | /** 52 | * Constructor to create a new root shell to run linux commands in 53 | */ 54 | public Shell() { 55 | this("su"); 56 | } 57 | 58 | public Shell setCommandListener(CommandListener listener) { 59 | return setCommandListener(null, listener); 60 | } 61 | 62 | public Shell setCommandListener(Handler handler, CommandListener listener) { 63 | mHandler = handler; 64 | mListener = listener; 65 | return this; 66 | } 67 | 68 | public static class SU { 69 | public static CommandResult run(String...commands) { 70 | return new Shell("su").run(commands); 71 | } 72 | public static CommandResult run(List commands) { 73 | return run(commands.toArray(new String[]{})); 74 | } 75 | } 76 | 77 | public static class SH { 78 | public static CommandResult run(String...commands) { 79 | return new Shell("sh").run(commands); 80 | } 81 | public static CommandResult run(List commands) { 82 | return run(commands.toArray(new String[]{})); 83 | } 84 | } 85 | 86 | public static Shell.CommandResult run(String shell, String[] commands) { 87 | return new Shell(shell).run(commands); 88 | } 89 | 90 | /** 91 | * 92 | * @return The current shell commands are being executed in. 93 | */ 94 | public String getShell() { 95 | return shell; 96 | } 97 | 98 | /** 99 | * Sets the current shell to execute commands in. 100 | * @see #SU 101 | * @see #SH 102 | * @see #BASH 103 | * @param shell 104 | */ 105 | public void setShell(String shell) { 106 | this.shell = shell; 107 | } 108 | 109 | /** 110 | * Contains information about the last run command. 111 | */ 112 | public static class CommandResult { 113 | /** The exit value returned by the last run command. -1 by default. **/ 114 | public int exitValue = -1; 115 | /** Standard output of all commands run **/ 116 | public String stdout; 117 | /** Standard error by all commands run **/ 118 | public String stderr; 119 | 120 | public CommandResult() { 121 | 122 | } 123 | 124 | public CommandResult(int exitValue, String stdout, String stderr) { 125 | this.exitValue = exitValue; 126 | this.stdout = stdout; 127 | this.stderr = stderr; 128 | } 129 | 130 | /** 131 | * 132 | * @return true if the {@link #exitValue} is equal to 0. 133 | */ 134 | public boolean success() { 135 | return exitValue == 0; 136 | } 137 | 138 | public boolean hasOutput() { 139 | return !TextUtils.isEmpty(this.stdout); 140 | } 141 | 142 | public boolean isSuccess() { 143 | return success() && hasOutput(); 144 | } 145 | } 146 | 147 | private void onReadLine(final String line, final boolean stdout) { 148 | if (mListener != null) { 149 | if (mHandler != null) { 150 | mHandler.post(new Runnable() { 151 | @Override 152 | public void run() { 153 | mListener.onReadOutput(line, stdout); 154 | } 155 | }); 156 | } else { 157 | mListener.onReadOutput(line, stdout); 158 | } 159 | } 160 | } 161 | 162 | private String readStream(InputStreamReader stream, boolean stdout) { 163 | BufferedReader reader = new BufferedReader(stream); 164 | StringBuffer buffer = null; 165 | try { 166 | String line = reader.readLine(); 167 | if (line != null) { 168 | buffer = new StringBuffer(line); 169 | while ((line = reader.readLine()) != null) { 170 | onReadLine(line, stdout); 171 | buffer.append("\n").append(line); 172 | } 173 | } 174 | } catch (IOException e) { 175 | Log.i(TAG, "Error: " + e.getMessage()); 176 | } 177 | 178 | if (buffer != null) { 179 | return buffer.toString(); 180 | } 181 | 182 | return null; 183 | } 184 | 185 | /** 186 | * Runs commands in the current shell. 187 | * 188 | * @param commands A single or an array of commands the current {@link #shell} should run. 189 | * @return The result (see {@linkplain CommandResult}) of all the commands run. 190 | */ 191 | public CommandResult run(String... commands) { 192 | final CommandResult result = new CommandResult(); 193 | InputStreamReader osStdout = null; 194 | InputStreamReader osStderr = null; 195 | DataOutputStream os = null; 196 | Process process = null; 197 | Runtime.getRuntime().gc(); 198 | 199 | try { 200 | process = Runtime.getRuntime().exec(shell); 201 | os = new DataOutputStream(process.getOutputStream()); 202 | osStdout = new InputStreamReader(process.getInputStream()); 203 | osStderr = new InputStreamReader(process.getErrorStream()); 204 | 205 | try { 206 | for (String command : commands) { 207 | 208 | if (shell.equals("su") && LD_LIBRARY_PATH != null) { 209 | // On some versions of Android (ICS) LD_LIBRARY_PATH is unset when using su 210 | // We need to pass LD_LIBRARY_PATH over su for some commands to work correctly. 211 | command = "LD_LIBRARY_PATH=" + LD_LIBRARY_PATH + " " + command; 212 | } 213 | 214 | if (mListener != null) { 215 | if (mHandler != null) { 216 | final String cmd = command; 217 | mHandler.post(new Runnable() { 218 | @Override 219 | public void run() { 220 | mListener.onExecuteCommand(cmd); 221 | } 222 | }); 223 | } else { 224 | mListener.onExecuteCommand(command); 225 | } 226 | } 227 | 228 | os.writeBytes(command + "\n"); 229 | os.flush(); 230 | } 231 | 232 | os.writeBytes("exit\n"); 233 | os.flush(); 234 | 235 | result.stdout = readStream(osStdout, true); 236 | result.stderr = readStream(osStderr, false); 237 | result.exitValue = process.waitFor(); 238 | } catch (InterruptedException e) { 239 | Log.i(TAG, "Error running commands: " + e.getMessage(), e); 240 | } catch (Exception e) { 241 | Log.i(TAG, "Error running commands: " + e.getMessage(), e); 242 | } 243 | } catch (IOException e) { 244 | Log.i(TAG, "Error: " + e.getMessage()); 245 | } finally { 246 | try { 247 | if (os != null) { 248 | os.close(); 249 | } 250 | if (osStdout != null) { 251 | osStdout.close(); 252 | } 253 | if (osStderr != null) { 254 | osStderr.close(); 255 | } 256 | if (process != null) { 257 | process.destroy(); 258 | } 259 | } catch (Exception ignore) { } 260 | } 261 | 262 | if (mListener != null) { 263 | if (mHandler != null) { 264 | mHandler.post(new Runnable() { 265 | @Override 266 | public void run() { 267 | mListener.onFinished(result); 268 | } 269 | }); 270 | } else { 271 | mListener.onFinished(result); 272 | } 273 | } 274 | 275 | return result; 276 | } 277 | 278 | /** 279 | * Checks if the user is rooted
280 | * forceCheck defaults to false 281 | * @see #canSu(boolean) 282 | */ 283 | public static boolean canSu() { 284 | return canSu(false); 285 | } 286 | 287 | /** 288 | * Checks if the user has root access. 289 | * @param forceCheck Set to true to check for root 290 | * regardless if it has already been checked. 291 | * @return true if the user has root access. 292 | */ 293 | public static boolean canSu(boolean forceCheck) { 294 | if (canSu == null || forceCheck) { 295 | CommandResult r = SU.run("id"); 296 | StringBuilder out = new StringBuilder(); 297 | 298 | if (r.stdout != null) { 299 | out.append(r.stdout).append(" ; "); 300 | } 301 | if (r.stderr != null) { 302 | out.append(r.stderr); 303 | } 304 | Log.d(TAG, "canSU() su[" + r.exitValue + "]: " + out); 305 | canSu = r.success(); 306 | } 307 | 308 | return canSu; 309 | } 310 | 311 | } 312 | -------------------------------------------------------------------------------- /app/src/main/libs/android-support-v4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/libs/android-support-v4.jar -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_action_new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable-hdpi/ic_action_new.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_action_new_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable-hdpi/ic_action_new_dark.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_action_phone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable-hdpi/ic_action_phone.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_action_phone_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable-hdpi/ic_action_phone_dark.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_action_sd_storage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable-hdpi/ic_action_sd_storage.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_action_sd_storage_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable-hdpi/ic_action_sd_storage_dark.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable-hdpi/icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-ldpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable-ldpi/icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_action_new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable-mdpi/ic_action_new.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_action_new_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable-mdpi/ic_action_new_dark.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_action_phone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable-mdpi/ic_action_phone.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_action_phone_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable-mdpi/ic_action_phone_dark.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_action_sd_storage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable-mdpi/ic_action_sd_storage.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_action_sd_storage_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable-mdpi/ic_action_sd_storage_dark.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable-mdpi/icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_action_new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable-xhdpi/ic_action_new.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_action_new_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable-xhdpi/ic_action_new_dark.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_action_phone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable-xhdpi/ic_action_phone.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_action_phone_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable-xhdpi/ic_action_phone_dark.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_action_sd_storage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable-xhdpi/ic_action_sd_storage.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_action_sd_storage_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable-xhdpi/ic_action_sd_storage_dark.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable-xhdpi/icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_action_new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable-xxhdpi/ic_action_new.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_action_new_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable-xxhdpi/ic_action_new_dark.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_action_phone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable-xxhdpi/ic_action_phone.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_action_phone_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable-xxhdpi/ic_action_phone_dark.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_action_sd_storage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable-xxhdpi/ic_action_sd_storage.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_action_sd_storage_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable-xxhdpi/ic_action_sd_storage_dark.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable-xxhdpi/icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable-xxxhdpi/icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/dark_divider.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_action_save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable/ic_action_save.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_file_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable/ic_file_dark.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_file_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable/ic_file_light.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_folder_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable/ic_folder_dark.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_folder_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable/ic_folder_light.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_folder_up_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable/ic_folder_up_dark.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_folder_up_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable/ic_folder_up_light.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_change_folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable/ic_menu_change_folder.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/light_divider.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/menu_auto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable/menu_auto.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/menu_auto_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable/menu_auto_selected.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/menu_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable/menu_back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/menu_change_speed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable/menu_change_speed.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/menu_change_speed_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable/menu_change_speed_selected.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/menu_mouse_right_click.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable/menu_mouse_right_click.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/menu_mouse_scroll_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable/menu_mouse_scroll_down.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/menu_mouse_scroll_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable/menu_mouse_scroll_up.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/menu_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable/menu_settings.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/menu_skip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable/menu_skip.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/menu_skip_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/app/src/main/res/drawable/menu_skip_selected.png -------------------------------------------------------------------------------- /app/src/main/res/layout/about_preference_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 18 | 26 | 29 | 32 | 35 | 36 | 40 | 43 | 45 | 46 | 51 | 55 | 58 | 61 | 64 | 65 | 68 | 71 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /app/src/main/res/layout/change_log_entry.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 13 | 20 | 27 | 28 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/layout/copy_file_dialog.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 11 | 17 | 20 | 21 | 25 | 31 | 35 | 36 | 37 | 38 | 43 | 50 | 51 | 52 | 57 | 64 | 65 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_preference.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 18 | 19 | 26 | 27 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/res/layout/file_system_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 13 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fix_dialog.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 12 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/layout/folder_browser_dialog.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 14 | 21 | 31 | 37 | 44 | 51 | 52 | 53 | 58 | 59 | -------------------------------------------------------------------------------- /app/src/main/res/layout/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/layout/onscripter.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 11 | 17 | 21 | 26 | 31 | 36 | 37 | 43 | 47 | 51 | 55 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /app/src/main/res/layout/radiobutton_choice_item.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/sdcard_fix_su_dialog.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 13 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/layout/selective_file_dialog.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 12 | 18 | 21 | 22 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/selective_file_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/layout/vnsettings_dialog.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 11 | 15 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/vnsettings_dialog_controls.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 11 | 16 | 18 | 21 | 24 | 25 | 27 | 30 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /app/src/main/res/layout/vnsettings_dialog_text.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 13 | 17 | 23 | 27 | 28 | 34 | 40 | 41 | 46 | 47 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 16 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/values-ja/change_log.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 変更 4 | 5 | vバージョン 1.2.5,2018年9月29日 6 | バグを直した 7 | vバージョン 1.2.4,2015年8月7日 8 | たくさんバグを直した 9 | vバージョン 1.2.3,2015年7月25日 10 | ビデオが直した 11 | たくさんバグを直した 12 | vバージョン 1.2.2,2015年3月20日 13 | たくさんバグを直した 14 | vバージョン 1.2.1,2015年3月3日 15 | たくさんバグを直した 16 | vバージョン 1.2.0,2015年2月17日 17 | +中国 18 | vバージョン 1.1.18,2015年1月30日 19 | ビデオが直した (例:シークレットゲーム) 20 | vバージョン 1.1.17,2014年12月24日 21 | たくさんバグを直した 22 | vバージョン 1.1.16,2014年12月15日 23 | アンドロイドLのセーブスクリーンを直した 24 | たくさんバグを直した 25 | vバージョン 1.1.15,2014年12月1日 26 | たくさんバグを直した 27 | vバージョン 1.1.14,2014年11月24日 28 | +高音質オーディオ 29 | vバージョン 1.1.13,2014年11月20日 30 | 外部ストレージを使用することができなかったキットカットの大きな短所を迂回するように修正しました。 31 | ルーティングユーザのためにSDカードをアクセスできる権限を追加しました。 32 | キットカットの全体画面機能を追加しました。 33 | テキストプレビューが出なかったことを修正しました。 34 | vバージョン 1.1.12,2014年9月5日 35 | たくさんバグを直した 36 | vバージョン 1.1.11,2014年8月1日 37 | たくさんバグを直した 38 | vバージョン 1.1.10,2014年7月26日 39 | +ビデオのサポート 40 | vバージョン 1.1.9,2014年7月2日 41 | たくさんバグを直した 42 | vバージョン 1.1.8,2014年6月9日 43 | +ダークテーマ 44 | vバージョン 1.1.7,2014年5月29日 45 | +日本のメニュー 46 | 47 | 48 | -------------------------------------------------------------------------------- /app/src/main/res/values-ja/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | (バック) 4 | やめる 5 | 6 | 7 | 内蔵メモリを見つけることができません。何か間違っています! 8 | フォントをロードします… 9 | default.ttf が見つかりません! 10 | ディレクトリが見つかりません! 11 | 内蔵メモリにフォントを移動できません! 12 | フォントを読めません! 13 | 内蔵メモリがいっぱいになった。保存できません。 14 | 他のフォルダ名を選択してください 15 | 壊れたファイルをロードすることができません。\n別のファイルをロードしてください。 16 | ゲームを始めることができません。 現在、ゲームの必要なファイルが正しくない、又は不足します。\nゲームの必要なファイルを全てコピーしたのかしっかりチェックしてください。 17 | このゲームの中で複数のスクリプトファイルが発見されました。 そのうち最初のファイルだけが使用されます。\n\n使用されないファイル: 18 | 19 | 20 | 設定 21 | フォルダを変更する 22 | 23 | 24 | 全般 25 | 26 | レンダリング 27 | 文字を読みやすく輪郭を描きます。 28 | 文字の輪郭を描画する。 29 | 30 | コントロール 31 | スワイプするまでボタンを非表示。 32 | ボタンを表示するジェスチャー 33 | ジェスチャーに隠されたボタンを取り上げます。 34 | スワイプジェスチャー 35 | 36 | フォルダ 37 | ゲームが含まれているデフォルトのフォルダを設定します。 38 | デフォルトフォルダの設定 39 | 40 | アバウト 41 | 著者: 42 | バージョン: 43 | ウェブサイト: 44 | このアプリケーションのソースは無料です。もしこのコードを使用したい場合は、Studio OGA OgapeeとMatthew Ngとの下さるください。 45 | Studio O.G.A. Ogapee(オリジナル製作)には、アプリケーションのソースを提供したことに対して感謝の意を表します。 46 | 47 | 変更 48 | 49 | 外観 50 | テーマ 51 | 52 | 53 | @string/settings_theme_default_entry 54 | 55 | 56 | 57 | 再生 58 | 外部ビデオプレーヤーを使う 59 | 高音質オーディオ使用 60 | 61 | 62 | フォルダを選ぶ 63 | 選択 64 | バック 65 | 66 | 終了 67 | リブート 68 | 69 | 新しいフォルダー 70 | このアプリを評価! 71 | OK、 このメッセージを再表示しない 72 | 73 | 74 | コントロール 75 | 文字 76 | 77 | この設定は、すべてのゲームでデフォルトとして設定されます。 78 | 79 | 両側から押し 80 | 左から押し 81 | 右から押し 82 | 83 | ボタンを表示するジェスチャー 84 | スワイプジェスチャー 85 | 86 | 文字サイズを固定します。 87 | 文字サイズ: 88 | 日本語 89 | 90 | 91 | コピーが終了した。既存のフォルダを内部メモリに移しました。 92 | セーブファイルをコピー完了しました。 93 | コピーに失敗しました。 94 | 内部メモリがいっぱいになってゲームをコピーできません。 95 | コピーできるファイルがありません。 96 | アンドロイド4.4.Xバージョンのキットカットを使用するフォンの中には外部ストレージを使用できないように詰まっています。これがあなたがゲームをセーブしない理由です。\nの問題を修正ボタンを押してください。 97 | セーブフォルダが存在しません。 98 | あなたのSDカードはもう使用が可能です。そして内部メモリにセーブファイルがあります。このファイルを再び元のフォルダに回して欲しいですか? 99 | もうセーブファイルは元のフォルダに復帰しており、このアプリはセーブファイルをこれ以上他のフォルダに保存しません。 100 | SDカードの修正を失敗しました。なぜならplaform.xmlファイルが存在しません。 101 | システムを修正できません。携帯電話をまた始めてみますか?もしすでに再開をして見れば、matthewn4444@gmail.comメールに英語で連絡をください。 102 | システムを修正できません。matthewn4444@gmail.comメールに英語で連絡をください。. 103 | 修正が完了しました。機器を再起動させてください。 104 | 105 | セーブフォルダ変更 106 | 107 | セーブフォルダの選択 108 | 問題を修正 109 | ファイルをスキャン中 110 | ファイルをコピー中 111 | ファイルをコピーするフォルダ 112 | ファイル: 113 | サイズ: 114 | コピーするファイルを選んでください。 115 | 残容量: 116 | (どんなファイルで交代) 117 | この方法は、あなたのSDカードをアプリがアクセスが可能するようにシステムを修正します。\n\nこのアプリは問題を修正しながら起こった何事にも補償をすることはできません。\n\nシステム内部/system/etc/permissions/platform.xmlファイルにWRITE_EXTERNAL_STORAGEパーミッションを追加することで 118 | 選択によってこのアプリが貴方のシステムをアクセスすることに同意しました。 119 | 直しています… 120 | 121 | 122 | ゲームを内部メモリに移動 123 | ゲームのセーブファイルだけを内部メモリに移動 124 | SDカードをアクセス可能するように修正(ルーティングユーザ) 125 | 126 | 127 | -------------------------------------------------------------------------------- /app/src/main/res/values-ko/change_log.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 변경사항 4 | 5 | v버전 1.2.5,2018년 9월 29일 6 | 버그를 고쳤다 7 | v버전 1.2.4,2015년 8월 7일 8 | 고정 된 한국어 텍스트 (쓰르라미 울적에) 9 | v버전 1.2.3,2015년 7월 25일 10 | 비디오 고친 (달에 다가서는 소녀의 작법2, 나츠이로레시피) 11 | 많은 버그를 고쳤다 (리틀버스터즈) 12 | v버전 1.2.2,2015년 3월 20일 13 | 게임 고정: 예익의 유스티아, 점점 더 14 | v버전 1.2.1,2015년 3월 3일 15 | 고정된 게임을 16 | v버전 1.2.0,2015년 2월 17일 17 | +중국어 18 | v버전 1.1.18,2015년 1월 30일 19 | 비디오 고친 (Lovely Quest, Secret Game, Akatsuki no Goei) 20 | v버전 1.1.17,2014년 12월 24일 21 | 많은 버그를 고쳤다 22 | v버전 1.1.16,2014년 12월 15일 23 | 많이 게임을 고쳤다(새벽의 호위,크로스 채널,등). 24 | 안드로이드 L의 세이브 스크린을 고쳤다. 25 | v버전 1.1.15,2014년 12월 1일 26 | 많은 버그를 고쳤다 27 | v버전 1.1.14,2014년 11월 24일 28 | +고음질 오디오 29 | 추락하는 고정형 비디오 플레이어 30 | v버전 1.1.13,2014년 11월 20일 31 | 외부저장소를 사용할 수 없던 킷캣의 큰 단점을 우회하도록 수정하였습니다. 32 | 루팅 유저를 위해 SD카드를 접근 할 수 있는 권한을 추가 하였습니다. 33 | 킷켓의 전체화면 기능을 추가했습니다. 34 | 텍스트 프리뷰가 안나오던 것을 수정하였습니다. 35 | v버전 1.1.12,2014년 9월 5일 36 | 많은 버그를 고쳤다 37 | v버전 1.1.11,2014년 8월 1일 38 | 많은 버그를 고쳤다 39 | v버전 1.1.10,2014년 7월 26일 40 | +비디오 지원 41 | v버전 1.1.9,2014년 7월 2일 42 | 많은 버그를 고쳤다 43 | v버전 1.1.8,2014년 6월 9일 44 | +어두운 테마 45 | v버전 1.1.7,2014년 5월 29일 46 | +일본의 메뉴 47 | v버전 1.1.6,2014년 5월 7일 48 | 러시아어 49 | v버전 1.1.5,2014년 4월 16일 50 | 일반적인 한글 인코딩(ANSI, EUC-KR)스크립트로 게임실행가능 51 | 52 | 53 | -------------------------------------------------------------------------------- /app/src/main/res/values-ko/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 온스크립터 플러스 (광고 무료) 4 | 5 | (뒤로가기) 6 | 종료 7 | 8 | 9 | 내장 메모리를 찾을 수 없습니다. 무언가 잘못 되었습니다! 10 | …폰트 로딩중 11 | default.ttf 파일을 찾을 수 없습니다! 12 | 디렉토리를 찾을 수 없습니다! 13 | 내장 메모리로 폰트를 옮길 수 없습니다! 14 | 폰트를 읽을 수 없습니다! 15 | 내장 메모리가 가득 찼습니다. 저장할 수 없습니다 16 | 다른 폴더 이름을 선택하십시오 17 | 망가진 파일을 로드할 수 없습니다.\n다른 파일을 로드하세요. 18 | 게임을 시작할 수 없습니다. 현재 게임의 필요한 파일이 올바르지 않거나 부족합니다.\n게임의 필요한 파일을 전부 복사했는지 확실히 체크해 주세요. 19 | 이 게임안에서 여러개의 스크립트 파일이 발견되었습니다. 그 중 가장 처음의 파일만 사용됩니다. \n\n사용되지 않는 파일 : 20 | 21 | 22 | 설정 23 | 폴더 바꾸기 24 | 25 | 26 | 일반 27 | 28 | 렌더 29 | 글자를 읽기 쉽게 윤곽선을 그립니다. 30 | 글자에 윤곽선 그리기. 31 | 32 | 컨트롤 33 | 스와이프 하기 전까지 버튼을 숨깁니다. 34 | 버튼을 표시하기 위한 제스처. 35 | 제스처로 숨겨진 버튼을 불러옵니다. 36 | 스와이프 제스처 37 | 38 | 폴더 39 | 게임이 들어있는 기본 폴더를 설정합니다. 40 | 기본 폴더 설정 41 | 42 | 어플에 대하여 43 | 제작자: 44 | 버전: 45 | 웹사이트: 46 | 이 어플리케이션 소스는 무료입니다. 만약 이 코드를 사용하고자 한다면, Studio O.G.A. Ogapee 와 Matthew Ng에게 연락해주시길 바랍니다. 47 | Studio O.G.A. Ogapee (오리지널 제작자)에게 이 어플과 소스를 제공한 것에 대해 감사를 표합니다.\n이 어플을 한글로 번역해주신 MadZun에게 감사를 표합니다.\n(http://madzun.blog.me) 48 | 49 | 변경사항 50 | 51 | 외관 52 | 테마 53 | 화이트 54 | 55 | @string/settings_theme_default_entry 56 | 검정 57 | 58 | 59 | 재생 60 | 외부 비디오 플레이어를 사용 61 | 고음질 오디오 사용 62 | 63 | 64 | 폴더 고르기 65 | 선택 66 | 뒤로 67 | 다음 68 | 어플 종료 69 | 재부팅 70 | 71 | 새로운 폴더 72 | 이 앱을 평가! 73 | 네, 그만 보여주세요 74 | 75 | 76 | @string/settings_controls_cate 77 | 본문 78 | 79 | 이 설정은 모든 게임에서 기본으로 설정됩니다. 80 | 81 | 양쪽에서 밀기 82 | 왼쪽에서 밀기 83 | 오른쪽에서 밀기 84 | 85 | 버튼을 표시하기 위한 제스처. 86 | 스와이프 제스처 87 | 88 | 글자 크기를 고정시킵니다. 89 | 글자 크기: 90 | 한국어 日本語 91 | 92 | 93 | 복사 완료. 기존 폴더를 내부저장소로 옮겼습니다. 94 | 세이브 파일을 복사 완료하였습니다. 95 | 복사 실패. 96 | 내부 저장소가 가득 차서 게임을 복사 할 수 없습니다. 97 | 복사 할 수 있는 파일이 없습니다. 98 | 안드로이드 4.4.X 버전의 킷켓을 사용하는 폰들 중에는 외부 저장소를 사용 할 수 없도록 막혀있기도 합니다. 이것이 당신이 게임을 세이브 하지 못하는 이유입니다..\n문제를 수정 버튼을 눌러주세요. 99 | 세이브 폴더가 존재하지 않습니다. 100 | 당신의 SD카드는 이제 사용이 가능합니다. 그리고 내부저장소에 세이브 파일들이 있습니다. 이 파일을 다시 원래의 폴더로 돌리길 원하십니까? 101 | 이제 세이브 파일들은 원래의 폴더로 돌아갔고 온스크립터 플러스는 세이브 파일을 더 이상 다른 폴더에 저장하지 않습니다. 102 | SD카드의 수정을 실패하였습니다. 왜냐하면 plaform.xml 파일이 존재하지 않습니다. 103 | 시스템을 수정할 수 없습니다. 핸드폰을 다시 시작 해보시겠습니까? 만약 이미 다시 시작을 해 보았다면, matthewn4444@gmail.com 메일에 영어로 연락을 주세요. 104 | 시스템을 수정할 수 없습니다. matthewn4444@gmail.com 메일로 영어로 연락을 주세요. 105 | 수정이 완료 되었습니다. 기기를 재부팅 하여 주십시오. 106 | 107 | 세이브 폴더 변경 108 | 109 | 세이브 폴더 선택 110 | 문제를 수정 111 | 파일을 스캔중 112 | 파일을 복사중 113 | 파일을 복사할 폴더 114 | 파일: 115 | 크기: 116 | 복사 할 파일을 고르세요. 117 | 남은 용량: 118 | (어떤 파일로 교체) 119 | 이 방법은 당신의 SD카드를 어플이 접근이 가능하도록 시스템을 수정합니다.\n\n이 어플은 이 문제를 수정하면서 일어나는 어떠한 일에도 보상을 할 수 없습니다.\n\n시스템 내부 /system/etc/permissions/platform.xml 파일에 WRITE_EXTERNAL_STORAGE 퍼미션을 추가할 것입니다. 120 | 선택의 의해 이 온스크립터 플러스가 당신의 시스템을 접근하도록 동의했습니다. 121 | 수정중… 122 | 123 | 124 | 게임을 내부 저장소로 이동 125 | 게임의 세이브 파일만 내부 저장소로 이동 126 | SD카드를 접근 가능하도록 수정(루팅유저) 127 | 128 | 129 | -------------------------------------------------------------------------------- /app/src/main/res/values-ru/change_log.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Последние изменения 4 | 5 | vVersion 1.2.5,9/29/2018 6 | Исправлено ошибок 7 | vVersion 1.2.4,8/7/2015 8 | Исправлено множество ошибок 9 | vVersion 1.2.3,7/25/2015 10 | фиксированная видео (Little Busters, Natsuiro Recipe) 11 | vVersion 1.2.2,3/20/2015 12 | исправлены некоторые игры: Kagetsu Toyha, Umineko 13 | vVersion 1.2.1,3/3/2015 14 | Исправлено сохранение игры 15 | vVersion 1.2.0,2/17/2015 16 | +китайский 17 | Исправления Tsukihime Demo 18 | vVersion 1.1.18,1/30/2015 19 | фиксированная видео (Lovely Quest, Secret Game, Akatsuki no Goei) 20 | vVersion 1.1.17,12/24/2014 21 | Исправлено множество ошибок 22 | vVersion 1.1.16,12/15/2014 23 | Исправлено множество ошибок 24 | vVersion 1.1.15,12/1/2014 25 | Исправлено множество ошибок 26 | vVersion 1.1.14,11/20/2014 27 | Добавил выше Выбор качества в настройках 28 | vVersion 1.1.13,11/20/2014 29 | Исправлена проблема сохранения на внешнюю SD карту в Android Kitkat 30 | Добавлен фикс возможности записи на SD карту пользователям с правами root 31 | Добавлен режим погружения (полный экран) в Android Kitkat 32 | Исправлены некоторые проблемы размещения текста 33 | vVersion 1.1.12,9/5/2014 34 | Исправлено множество ошибок 35 | vVersion 1.1.11,8/1/2014 36 | Исправлено множество ошибок 37 | vVersion 1.1.10,7/26/2014 38 | добавлена поддержка видео 39 | vVersion 1.1.9,7/2/2014 40 | Исправлено множество ошибок 41 | vVersion 1.1.8,6/9/2014 42 | +темная тема 43 | vVersion 1.1.7,5/29/2014 44 | добавил японское меню 45 | vVersion 1.1.6,5/7/2014 46 | Добавлена поддержка русского текста в приложении 47 | 48 | 49 | -------------------------------------------------------------------------------- /app/src/main/res/values-ru/strings.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | (Назад) 4 | Выход 5 | 6 | 7 | Не найдена внутренняя память, что-то пошло не так! 8 | Загрузка шрифтов… 9 | Не удалось найти файл шрифта по умолчанию в папке assets! 10 | Не удалось найти папку private! 11 | Не удалось записать файл шрифта во внутреннею память! 12 | Не удалось загрузить шрифт! 13 | Внутренняя память заполнена и не может спасти. 14 | Пожалуйста, выберите другое имя 15 | Не удается загрузить поврежденный файл.\nПожалуйста, загрузите другой файл. 16 | Игра вылетает при запуске, возможно потому что отсутствуют некоторые файлы игры или они повреждены.\nПожалуйста, убедитесь, что вы скопировали все файлы игры должным образом. 17 | Найдено несколько скриптов для этой игры, перечисленных ниже. Будет использоваться только один скрипт, находящийся непосредственно в папке игры.\n\nНеиспользуемые: 18 | 19 | 20 | Настройки 21 | Сменить папку 22 | 23 | 24 | общие 25 | 26 | Видео настройки 27 | Отображает контур для каждого символа для удобства чтения. 28 | Отображение контура шрифта 29 | 30 | Управление 31 | Скрывает кнопки, пока пользователь не проведет по экрану, чтобы отобразить их. 32 | Провести по экрану, чтобы отобразить кнопки. 33 | Жест чтобы отобразить кнопки, когда они спрятаны. 34 | Провести по экрану 35 | 36 | Папка 37 | Выберите местоположение папки по умолчанию для чтения визуальных романов. 38 | Выберите папку по умолчанию 39 | 40 | О программе 41 | Автор: 42 | Version: 43 | Website: 44 | Это приложение бесплатно и с открытым исходным кодом. Если вы планируете использовать код, пожалуйста, укажите Studio Oga Ogapee и Matthew Ng. 45 | Благодаря Studio O.G.A. Ogapee (первый автор) возможно запустить это приложение. 46 | 47 | Посмотреть журнал изменений 48 | 49 | внешний вид 50 | тема 51 | белый 52 | 53 | @string/settings_theme_default_entry 54 | черный 55 | 56 | 57 | Воспроизведение 58 | Используйте внешний видеоплеер 59 | Использовать высокое качество звука 60 | 61 | 62 | Выберите папку 63 | Выбрать 64 | Назад 65 | Далее 66 | Закрыть приложение 67 | Перезагрузить 68 | Отправте письмо местоположением sdcard на matthewn4444@gmail.com. 69 | Что-бы добавить перевод для вашего языка напишите мне 70 | Создать новую папку 71 | Оцените приложение 72 | ОК, больше не показывать 73 | 74 | 75 | Управление 76 | Текст 77 | 78 | Глобальные настройки управления 79 | 80 | Проведите с двух сторон 81 | Проведите по экрану слева 82 | Проведите по экрану справа 83 | 84 | Провести по экрану 85 | 86 | 87 | Установите масштабирование текста 88 | Масштаб текста: 89 | Русский 日本語 90 | 91 | 92 | Копирование завершено. Теперь папка по умолчанию во внутренней памяти. 93 | Копирование сохранений завершено. 94 | Не удалось выполнить копирование. 95 | Внутренняя память заполнена, нельзя скопировать файлы игры. 96 | Нет файлов для копирования. 97 | Начиная с Android Kitkat 4.4.X, некоторые телефоны заблокировали доступ записи на внешнюю SD карту. Это причина почему вы не можете сохранить. \nПожалуйста выберите, как исправить эту проблему. 98 | Папка сохранений не существует. 99 | Теперь возможна запись на SD карту, но у вас есть файлы сохранений во внутренней памяти, вы бы хотели переместить их? 100 | Теперь возможна запись. Вам нужно скопировать сохранения из папки сохранений в папку с игрой. Сейчас приложение будет читать сохранения из папки игры, а не из папки сохранений. 101 | Не удается исправить разрешение на запись на внешнюю SD карту, потому что platform.xml не существует. 102 | Нельзя применить исправления к системе, вы пробовали перезагрузить? Если вы уже пробовали перезагрузиться, просьба сообщить об этом в matthewn4444@gmail.com. 103 | Не удается изменить системные файлы. Пожалуйста сообщите об этом matthewn4444@gmail.com. 104 | Чтобы применить изменения перезагрузите устройство. 105 | 106 | Изменить папку сохранений 107 | 108 | Выбрать папку сохранений 109 | Выберите способ исправить сохранения 110 | Сканирование файлов 111 | Копирование файлов 112 | Выберите назначение копирования 113 | Файл: 114 | Размер: 115 | Выбрать файлы для копирования 116 | Осталось свободного места: 117 | (Замена некоторых файлов) 118 | Эта операция исправит запись на внешнюю SD карту. Она изменяет системные файлы.\n\n Автор приложения не несет ответственности за возникшие проблемы с телефоном. Согласившись, вы несете ответственность за любые проблемы, которые могут случиться, в том числе, что телефон перестанет работать.\n\nБудет записано разрешение WRITE_EXTERNAL_STORAGE «media_rw» в файл /system/etc/permissions/platform.xml. 119 | Выбрав, вы соглашаетесь с тем, что это приложение измененит системные файлы с правами суперпользователя. 120 | Применение исправления… 121 | 122 | 123 | Переместить ваши игры в папку внутренней памяти 124 | Переместить только ваши сохранения в папку внутренней памяти 125 | Применить исправление SD карты для этой проблемы (нужен root) 126 | 127 | -------------------------------------------------------------------------------- /app/src/main/res/values-xlarge/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 27dp 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/values-zh/change_log.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 改动日志 4 | 5 | v版本 1.2.5,2018年9月29日 6 | 修正错误 7 | v版本 1.2.4,2015年8月7日 8 | 崩溃固定的游戏 (Moon of Darkness) 9 | v版本 1.2.3,2015年7月25日 10 | 视频被修理 11 | 修正错误 12 | v版本 1.2.2,2015年3月20日 13 | 修正错误 14 | v版本 1.2.1,2015年3月3日 15 | 修正错误 16 | v版本 1.2.0,2015年2月17日 17 | +中國 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/values-zh/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | (返回) 4 | 退出 5 | 6 | 7 | 找不到内部存储,出错! 8 | 加载字体中… 9 | 在assets中找不到默认字体文件! 10 | 找不到私人目录! 11 | 无法对内部存储读写字体文件! 12 | 无法读取字体! 13 | 没有足够的空间存储设置. 14 | 文件夹已存在,创建新文件夹. 15 | 存储文件已损坏无法加载. 请选择另一个. 16 | 此游戏在启动的时候崩溃,因为丢失或损坏的游戏文件。\n请确认您已经正确的复制所有游戏文件到指定文件夹 17 | "在下列游戏里发现多个文本文档。只有在游戏文件夹下的文本文档会被使用。\n\n未使用: 18 | 19 | 20 | 设置 21 | 改变文件 22 | 23 | 24 | 普通设置 25 | 26 | 渲染 27 | 为了方便阅读显示每个字母的轮廓. 28 | 渲染字体的轮廓 29 | 30 | 控制 31 | 在用户划动呼出控制前隐藏控制. 32 | 划动可见控制 33 | 呼出设置手势. 34 | 划动手势 35 | 36 | 文件夹 37 | 选择一个读取可见小说文件的默认文件夹位置. 38 | 选择默认文件夹 39 | 40 | 关于 41 | 作者: 42 | 版本: 43 | 网页: 44 | 此程序免费并开源. 如果你想用此程序的代码, 请提及 Studio O.G.A. Ogapee 和 Matthew Ng. 45 | 感谢 Studio O.G.A. Ogapee (原作者) 关于此程序的说明和源代码.。\n中文翻译:沈宇抗 46 | 47 | 看改动日志 48 | 49 | 外观 50 | 主题 51 | 52 | 53 | @string/settings_theme_default_entry 54 | 55 | 56 | 57 | 重放 58 | 使用外部播放器 59 | 使用高质量音频 60 | 61 | 62 | 选择文件夹 63 | 选择 64 | 返回 65 | 下一步 66 | 关闭程序 67 | 重启 68 | 用英语发送SD卡的位置信息到 matthewn4444@gmail.com 69 | 创建新文件夹 70 | 请给个好评! 71 | 好。不要在提示我了 72 | 73 | 74 | 控制 75 | 文本 76 | 77 | 这些控制设置全球通用. 78 | 79 | 从底部上划 80 | 从左部划动 81 | 从右部划动 82 | 83 | 划动打开设置 84 | 划动手势 85 | 86 | 设置放大字体大小. 87 | 大小比例: 88 | 中国 日本語 89 | 90 | 91 | 复制完成. 默认文件夹已被设置为内部存储. 92 | 已完成复制存档文件. 93 | 复制失败. 94 | 内部存储已满, 无法复制游戏文件. 95 | 找不到文件复制. 96 | 因为在安卓 Kitkat 4.4.X, 一些手机限制了此程序的权限所以无法在外部SD卡存档,这就是为什么无法存档.\n请选择如何修复此问题. 97 | 存档文件不存在. 98 | 现在可以读写SD卡,你在内部存储还有存档文件, 你想要将他们移动到此文件夹吗?. 99 | 现在已经可以读写. 你需要复制剩余的存档文件到原游戏文件夹. 此程序会读写游戏文件夹内部的存档文件而不是原存档文件夹. 100 | 因为 plaform.xml 不存在,无法对外置SD卡进行修复读取权限. 101 | 无法对系统进行修复, 请尝试重启? 如果已经重启过仍未修复, 请把这个问题上报到 matthewn4444@gmail.com. 102 | 无法改动系统文件. 请把这个问题上报到 matthewn4444@gmail.com. 103 | 为应用改动请重启设备. 104 | 105 | 改变存档文件夹 106 | 107 | 选择一个存档文件 108 | 选择如何修复 109 | 扫描文件 110 | 复制文件 111 | 选择目标文件夹 112 | 文件: 113 | 大小: 114 | 选择要复制的文件 115 | 剩余可用空间: 116 | (正在替换文件) 117 | 此操作会修复并可以读写外部SD卡存储. 并会用root权限修改系统文件.\n\n此程序对于修改产生的任何问题没有任何责任. \n\n这操作会写入 "media_rw" 到文件 /system/etc/permissions/platform.xml 在 WRITE_EXTERNAL_STORAGE 权限 118 | 你同意让这个程序用root权限修改系统文件. 119 | 正在修复… 120 | 121 | 122 | 将你的游戏移动到内部存储的文件夹 123 | 将你的游戏存档移动到内部存储的文件夹 124 | 对这个问题请使用SD卡修复\n(可能需要root) 125 | 126 | 127 | -------------------------------------------------------------------------------- /app/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/values/change_log.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10dp 4 | change.log.pref.key 5 | Recent Changes 6 | 7 | 8 | vVersion 1.2.5,9/29/2018 9 | Added a way to view sdcards, should work with most devices/versions, but may not work on some 10 | vVersion 1.2.4,8/7/2015 11 | Fixed freezing when not choosing an external video player 12 | Added more error messages for corrupted save files 13 | Fixed rendering text for all Korean games 14 | Blocked PONScripter games 15 | Fixed Moon of Darkness from crashing on startup (Chinese) 16 | vVersion 1.2.3,7/25/2015 17 | Fixed games crashing when \'#\' is used in the script 18 | Fixed a lot of videos that didn\'t run before (Umineko, Tsuki ni yorisou otome no sahou 2, etc) 19 | vVersion 1.2.2,3/20/2015 20 | Added "ext_card" and "MicroSD" paths as external sdcard cards 21 | Fix several Korean translated games (Hotch Kiss, Auyoki no Eustia, Princess Frontier) 22 | Unineko is playable 23 | Fixes some text glitches from Kagetsu Tohya 24 | vVersion 1.2.1,3/3/2015 25 | Fixes saving when not providing a save folder 26 | vVersion 1.2.0,2/17/2015 27 | Added Chinese language 28 | Fixes menu decoding when using different script language 29 | Changed preferences from xml to json 30 | Fixes Tsukihime Russian Demo so it can play 31 | vVersion 1.1.18,1/30/2015 32 | Fixed videos (Akatsuki no Goei, Lovely Quest, Secret Game, etc) 33 | vVersion 1.1.17,12/24/2014 34 | Prevent loading corrupted save files that causes crashes 35 | vVersion 1.1.16,12/15/2014 36 | Fixed freezing when turning phone on 37 | Fixed side controls from disappearing 38 | Fixed a bunch of Korean games (e.g Akatsuki no Goei, Cross channel, Nanatsu no Fushigi no Owaru Toki, etc) 39 | Fixed save/load slots layout 40 | vVersion 1.1.15,12/1/2014 41 | Fixed the black screen on Tsukihime 42 | Fixed loading issues with Kagetsu Toyha 43 | Fixed crashing on Gingerbread 44 | vVersion 1.1.14,11/24/2014 45 | Added higher quality option in settings 46 | Fixed video player from crashing 47 | Hid statusbar for Android 4.0–4.1 when playing a game 48 | Fixed Gingerbread crashing 49 | vVersion 1.1.13,11/20/2014 50 | Bypass Kitkat issue not able to save to external sdcard 51 | Added fix to allow rooted users to write to sdcard 52 | Added Kiktat immersion (fullscreen) mode 53 | Fixed some text placement issues 54 | vVersion 1.1.12,9/5/2014 55 | Added more sd card locations 56 | vVersion 1.1.11,8/1/2014 57 | Fixes typemoon games (eg. Kagetsu Tohya) 58 | Fixes bug that did not allow users to pick a custom font 59 | vVersion 1.1.10,7/26/2014 60 | Added video support 61 | Fixes controls for widescreen games 62 | Increased audio quality 63 | Reduced ad frequency 64 | vVersion 1.1.9,7/2/2014 65 | Fixed various bugs 66 | vVersion 1.1.8,6/9/2014 67 | Added Dark Theme 68 | vVersion 1.1.7,5/29/2014 69 | Added Japanese menu translation 70 | Fixed back button from the game 71 | vVersion 1.1.6,5/7/2014 72 | Added Russian support 73 | vVersion 1.1.5,4/16/2014 74 | Korean (Hangul) font is supported 75 | Fixes system text for each language 76 | 77 | 78 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 0dp 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/values/hidden_strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 738dc93d 4 | ca-app-pub-7827835196460106/7286598875 5 | ca-app-pub-7827835196460106/5549926473 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/style.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 15 | 16 | 17 | 22 | 25 | 26 | 27 | 32 | 37 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | 21 | 22 | 26 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/xml/about_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/xml/general_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 16 | 17 | 18 | 22 | 30 | 31 | 32 | 35 | 39 | 40 | 41 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /app/src/main/res/xml/settings_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 |
5 |
7 | 8 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | buildscript { 3 | repositories { 4 | jcenter() 5 | } 6 | dependencies { 7 | classpath 'com.android.tools.build:gradle:1.3.0' 8 | } 9 | } 10 | allprojects { 11 | repositories { 12 | jcenter() 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /design/buttons.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/design/buttons.psd -------------------------------------------------------------------------------- /design/feature-image.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/design/feature-image.psd -------------------------------------------------------------------------------- /design/folder.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/design/folder.psd -------------------------------------------------------------------------------- /design/icon.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/design/icon.psd -------------------------------------------------------------------------------- /design/screenshots/ja/screenshot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/design/screenshots/ja/screenshot1.png -------------------------------------------------------------------------------- /design/screenshots/ja/screenshot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/design/screenshots/ja/screenshot2.png -------------------------------------------------------------------------------- /design/screenshots/ja/screenshot3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/design/screenshots/ja/screenshot3.png -------------------------------------------------------------------------------- /design/screenshots/ja/screenshot4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/design/screenshots/ja/screenshot4.png -------------------------------------------------------------------------------- /design/screenshots/ja/screenshot5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/design/screenshots/ja/screenshot5.png -------------------------------------------------------------------------------- /design/screenshots/ja/screenshot6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/design/screenshots/ja/screenshot6.png -------------------------------------------------------------------------------- /design/screenshots/ko/screenshot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/design/screenshots/ko/screenshot1.png -------------------------------------------------------------------------------- /design/screenshots/ko/screenshot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/design/screenshots/ko/screenshot2.png -------------------------------------------------------------------------------- /design/screenshots/ko/screenshot3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/design/screenshots/ko/screenshot3.png -------------------------------------------------------------------------------- /design/screenshots/ko/screenshot4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/design/screenshots/ko/screenshot4.png -------------------------------------------------------------------------------- /design/screenshots/ko/screenshot5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/design/screenshots/ko/screenshot5.png -------------------------------------------------------------------------------- /design/screenshots/ru/screenshot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/design/screenshots/ru/screenshot1.png -------------------------------------------------------------------------------- /design/screenshots/ru/screenshot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/design/screenshots/ru/screenshot2.png -------------------------------------------------------------------------------- /design/screenshots/ru/screenshot3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/design/screenshots/ru/screenshot3.png -------------------------------------------------------------------------------- /design/screenshots/ru/screenshot4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/design/screenshots/ru/screenshot4.png -------------------------------------------------------------------------------- /design/screenshots/ru/screenshot5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/design/screenshots/ru/screenshot5.png -------------------------------------------------------------------------------- /design/screenshots/ru/screenshot6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/design/screenshots/ru/screenshot6.png -------------------------------------------------------------------------------- /design/screenshots/screenshot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/design/screenshots/screenshot1.png -------------------------------------------------------------------------------- /design/screenshots/screenshot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/design/screenshots/screenshot2.png -------------------------------------------------------------------------------- /design/screenshots/screenshot3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/design/screenshots/screenshot3.png -------------------------------------------------------------------------------- /design/screenshots/screenshot4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/design/screenshots/screenshot4.png -------------------------------------------------------------------------------- /design/screenshots/screenshot5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/design/screenshots/screenshot5.png -------------------------------------------------------------------------------- /design/screenshots/screenshot6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/design/screenshots/screenshot6.png -------------------------------------------------------------------------------- /design/screenshots/screenshot7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/design/screenshots/screenshot7.png -------------------------------------------------------------------------------- /design/screenshots/screenshot8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/design/screenshots/screenshot8.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewn4444/onscripter-plus-android/239c6c861757122d10a05beac0a311e6764db9bf/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Aug 09 18:09:25 PDT 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | include ':onscripter-engine-android' 3 | include ':VPlayer_library' 4 | project(':VPlayer_library').projectDir = new File(settingsDir, 'VPlayer_lib/VPlayer_library') 5 | --------------------------------------------------------------------------------