├── .gitignore ├── SideQuestLauncher ├── .gitignore ├── AppStarter │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── assets │ │ ├── firetv-home-icon.png │ │ └── firetv-settings-icon.png │ │ ├── ic_launcher-web.png │ │ ├── java │ │ └── com │ │ │ └── sidequest │ │ │ └── launcher │ │ │ ├── gui │ │ │ ├── AppActivity.java │ │ │ ├── AppSettingsOverlayDialog.java │ │ │ ├── CustomFragment.java │ │ │ ├── FileDialog.java │ │ │ ├── InfoOverlayDialog.java │ │ │ ├── InfosPrefActivity.java │ │ │ ├── InstalledAppsAdapter.java │ │ │ ├── LeftBarItemsListAdapter.java │ │ │ ├── MainActivity.java │ │ │ ├── PreferenceActivity.java │ │ │ ├── ResizeWidthAnimation.java │ │ │ ├── UpdaterActivity.java │ │ │ ├── UpdaterAppsAdapter.java │ │ │ ├── UpdaterDialogHandler.java │ │ │ └── WallpaperSelectDialog.java │ │ │ └── tools │ │ │ ├── AppInfo.java │ │ │ ├── AppStarter.java │ │ │ ├── AppStarterUpdater.java │ │ │ ├── KodiUpdater.java │ │ │ ├── SPMCUpdater.java │ │ │ ├── SettingsProvider.java │ │ │ ├── Tools.java │ │ │ ├── Updater.java │ │ │ └── ZipDirectory.java │ │ └── res │ │ ├── anim │ │ ├── appsettings_overlay_in.xml │ │ └── appsettings_overlay_out.xml │ │ ├── drawable │ │ ├── appdrawergriditembackground.xml │ │ ├── appselector.xml │ │ ├── appsettingsbackground.xml │ │ ├── appsettingsselector.xml │ │ ├── infooverlaybackground.xml │ │ ├── itemselector.xml │ │ ├── itemtextselector.xml │ │ └── mainbackground.xml │ │ ├── layout │ │ ├── appactivity.xml │ │ ├── appdrawergriditemlayout.xml │ │ ├── appdrawergriditemlayout_withbackground.xml │ │ ├── appsettingsoverlaydialog.xml │ │ ├── appupdateritemlayout.xml │ │ ├── infooverlaydialog.xml │ │ ├── leftbarlistitemlayout.xml │ │ ├── mainactivity.xml │ │ └── updateractivity.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-nodpi │ │ ├── app_settings.png │ │ ├── app_sort.png │ │ ├── appstarter_logo_only_white.png │ │ ├── appstarter_logo_only_white_middle.png │ │ └── appstarter_logo_only_white_small.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-cn │ │ └── strings.xml │ │ ├── values-de │ │ └── strings.xml │ │ ├── values-ru │ │ └── strings.xml │ │ ├── values-uk │ │ └── strings.xml │ │ ├── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ │ └── xml │ │ ├── infoprefactivity.xml │ │ └── preferencesactivity.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle ├── SideQuestWrapperHome ├── .gitignore ├── app │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── sidequest │ │ │ └── wrapper2 │ │ │ └── ExampleInstrumentedTest.java │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── sidequest │ │ │ │ └── wrapper2 │ │ │ │ └── MainActivity.java │ │ └── res │ │ │ ├── drawable-v24 │ │ │ └── ic_launcher_foreground.xml │ │ │ ├── drawable │ │ │ └── ic_launcher_background.xml │ │ │ ├── layout │ │ │ └── activity_main.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ └── values │ │ │ ├── colors.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ └── test │ │ └── java │ │ └── com │ │ └── sidequest │ │ └── wrapper2 │ │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle └── SideQuestWrapperTV ├── .gitignore ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── sidequest │ │ └── wrapper │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── sidequest │ │ │ └── wrapper │ │ │ └── MainActivity.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── sidequest │ └── wrapper │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.aar 4 | *.ap_ 5 | *.aab 6 | 7 | # Files for the ART/Dalvik VM 8 | *.dex 9 | 10 | # Java class files 11 | *.class 12 | 13 | # Generated files 14 | bin/ 15 | gen/ 16 | out/ 17 | # Uncomment the following line in case you need and you don't have the release build type files in your app 18 | # release/ 19 | 20 | # Gradle files 21 | .gradle/ 22 | build/ 23 | 24 | # Local configuration file (sdk path, etc) 25 | local.properties 26 | 27 | # Proguard folder generated by Eclipse 28 | proguard/ 29 | 30 | # Log Files 31 | *.log 32 | 33 | # Android Studio Navigation editor temp files 34 | .navigation/ 35 | 36 | # Android Studio captures folder 37 | captures/ 38 | 39 | # IntelliJ 40 | *.iml 41 | .idea/workspace.xml 42 | .idea/tasks.xml 43 | .idea/gradle.xml 44 | .idea/assetWizardSettings.xml 45 | .idea/dictionaries 46 | .idea/libraries 47 | # Android Studio 3 in .gitignore file. 48 | .idea/caches 49 | .idea/modules.xml 50 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you 51 | .idea/navEditor.xml 52 | 53 | # Keystore files 54 | # Uncomment the following lines if you do not want to check your keystore files in. 55 | #*.jks 56 | #*.keystore 57 | 58 | # External native build folder generated in Android Studio 2.2 and later 59 | .externalNativeBuild 60 | .cxx/ 61 | 62 | # Google Services (e.g. APIs or Firebase) 63 | # google-services.json 64 | 65 | # Freeline 66 | freeline.py 67 | freeline/ 68 | freeline_project_description.json 69 | 70 | # fastlane 71 | fastlane/report.xml 72 | fastlane/Preview.html 73 | fastlane/screenshots 74 | fastlane/test_output 75 | fastlane/readme.md 76 | 77 | # Version control 78 | vcs.xml 79 | 80 | # lint 81 | lint/intermediates/ 82 | lint/generated/ 83 | lint/outputs/ 84 | lint/tmp/ 85 | # lint/reports/ 86 | -------------------------------------------------------------------------------- /SideQuestLauncher/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/workspace.xml 4 | /.idea/libraries 5 | .DS_Store 6 | /build 7 | -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 29 5 | 6 | defaultConfig { 7 | minSdkVersion 24 8 | targetSdkVersion 24 9 | versionCode 24 10 | versionName "4.0.0" 11 | } 12 | 13 | compileOptions { 14 | sourceCompatibility JavaVersion.VERSION_1_7 15 | targetCompatibility JavaVersion.VERSION_1_7 16 | } 17 | buildTypes { 18 | release { 19 | minifyEnabled false 20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 21 | } 22 | } 23 | } 24 | 25 | dependencies { 26 | implementation fileTree(include: ['*.jar'], dir: 'libs') 27 | implementation 'com.android.support:appcompat-v7:22.2.1' 28 | implementation 'org.jsoup:jsoup:1.8.3' 29 | } -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /home/luki/Android/Sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 21 | 22 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/assets/firetv-home-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SideQuestVR/SideQuestAppLauncher/01b4f22d94592bcbe90d3a951b1c12131ef10e82/SideQuestLauncher/AppStarter/src/main/assets/firetv-home-icon.png -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/assets/firetv-settings-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SideQuestVR/SideQuestAppLauncher/01b4f22d94592bcbe90d3a951b1c12131ef10e82/SideQuestLauncher/AppStarter/src/main/assets/firetv-settings-icon.png -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SideQuestVR/SideQuestAppLauncher/01b4f22d94592bcbe90d3a951b1c12131ef10e82/SideQuestLauncher/AppStarter/src/main/ic_launcher-web.png -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/java/com/sidequest/launcher/gui/AppSettingsOverlayDialog.java: -------------------------------------------------------------------------------- 1 | package com.sidequest.launcher.gui; 2 | 3 | import android.app.Dialog; 4 | import android.app.DialogFragment; 5 | import android.os.Bundle; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.ImageView; 10 | import android.widget.LinearLayout; 11 | import android.widget.TextView; 12 | 13 | import com.sidequest.launcher.R; 14 | import com.sidequest.launcher.tools.AppInfo; 15 | 16 | /** 17 | * App Settings Overlay for additional settings per app 18 | */ 19 | public class AppSettingsOverlayDialog extends DialogFragment 20 | { 21 | public enum ActionEnum { NOTHING, SORT, SETTINGS } 22 | 23 | public static AppSettingsOverlayDialog newInstance(AppInfo appInfo) 24 | { 25 | // Create dialog and set custom style 26 | AppSettingsOverlayDialog dialog = new AppSettingsOverlayDialog(); 27 | dialog.setStyle(DialogFragment.STYLE_NO_FRAME, R.style.TransparentDialog); 28 | 29 | // Add needed stuff 30 | dialog.setAppInfo(appInfo); 31 | 32 | return dialog; 33 | } 34 | 35 | /** AppInfo of the current App */ 36 | private AppInfo mAppInfo; 37 | 38 | /** Action handler */ 39 | private OnActionClickedHandler onActionClickedHandler; 40 | 41 | /** 42 | * Default constructor required for DialogFragment 43 | */ 44 | public AppSettingsOverlayDialog() 45 | { 46 | } 47 | 48 | /** 49 | * Set the action click listener 50 | * @param listener 51 | */ 52 | public void setOnActionClickedHandler(OnActionClickedHandler listener) 53 | { 54 | onActionClickedHandler = listener; 55 | } 56 | 57 | /** 58 | * Sets the current AppInfo 59 | * @param appInfo 60 | */ 61 | public void setAppInfo(AppInfo appInfo) 62 | { 63 | mAppInfo = appInfo; 64 | } 65 | 66 | @Override 67 | public Dialog onCreateDialog(Bundle savedInstanceState) 68 | { 69 | final Dialog dialog = super.onCreateDialog(savedInstanceState); 70 | dialog.getWindow().getAttributes().windowAnimations = R.style.DialogAnimation; 71 | return dialog; 72 | } 73 | 74 | @Override 75 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 76 | { 77 | // Create view 78 | View view = inflater.inflate(R.layout.appsettingsoverlaydialog, container); 79 | 80 | // Set text, icons and click-handler 81 | TextView title = (TextView) view.findViewById(R.id.title); 82 | title.setText(mAppInfo.getDisplayName()); 83 | 84 | ImageView appIcon = (ImageView) view.findViewById(R.id.appIcon); 85 | appIcon.setImageDrawable(mAppInfo.getDisplayIcon()); 86 | 87 | LinearLayout appSort = (LinearLayout) view.findViewById(R.id.appSort); 88 | appSort.setOnClickListener(new View.OnClickListener() 89 | { 90 | @Override 91 | public void onClick(View v) 92 | { 93 | fireActionClicked(ActionEnum.SORT); 94 | } 95 | }); 96 | 97 | LinearLayout appSettings = (LinearLayout) view.findViewById(R.id.appSettings); 98 | appSettings.setOnClickListener(new View.OnClickListener() 99 | { 100 | @Override 101 | public void onClick(View v) 102 | { 103 | fireActionClicked(ActionEnum.SETTINGS); 104 | } 105 | }); 106 | 107 | return view; 108 | } 109 | 110 | private void fireActionClicked(ActionEnum action) 111 | { 112 | if(onActionClickedHandler != null) 113 | { 114 | onActionClickedHandler.onActionClicked(action); 115 | } 116 | } 117 | 118 | /** 119 | * Interface for a service error 120 | */ 121 | public interface OnActionClickedHandler 122 | { 123 | public void onActionClicked(ActionEnum action); 124 | } 125 | } -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/java/com/sidequest/launcher/gui/CustomFragment.java: -------------------------------------------------------------------------------- 1 | package com.sidequest.launcher.gui; 2 | 3 | import android.app.Fragment; 4 | import android.view.KeyEvent; 5 | 6 | /** 7 | * Fragement that has additional features 8 | */ 9 | public class CustomFragment extends Fragment 10 | { 11 | /** 12 | * Custom on backpressed method 13 | */ 14 | public boolean onBackPressed() 15 | { 16 | return false; 17 | } 18 | 19 | public boolean onKeyDown(int keycode, KeyEvent e) 20 | { 21 | return false; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/java/com/sidequest/launcher/gui/FileDialog.java: -------------------------------------------------------------------------------- 1 | package com.sidequest.launcher.gui; 2 | 3 | import android.app.Activity; 4 | import android.app.AlertDialog; 5 | import android.app.Dialog; 6 | import android.content.DialogInterface; 7 | import android.os.Environment; 8 | import android.util.Log; 9 | 10 | import java.io.File; 11 | import java.io.FilenameFilter; 12 | import java.util.ArrayList; 13 | import java.util.Collections; 14 | import java.util.List; 15 | 16 | /** 17 | * Created by luki on 27.06.15. 18 | */ 19 | public class FileDialog 20 | { 21 | private static final String PARENT_DIR = ".."; 22 | private final String TAG = getClass().getName(); 23 | private String[] fileList; 24 | private File currentPath; 25 | 26 | public interface FileSelectedListener 27 | { 28 | void fileSelected(File file); 29 | } 30 | 31 | public interface DirectorySelectedListener 32 | { 33 | void directorySelected(File directory); 34 | } 35 | 36 | private ListenerList fileListenerList = new ListenerList(); 37 | private ListenerList dirListenerList = new ListenerList(); 38 | private final Activity activity; 39 | private boolean selectDirectoryOption; 40 | private String[] fileEndsWith; 41 | 42 | /** 43 | * @param activity 44 | * @param path 45 | */ 46 | public FileDialog(Activity activity, File path) 47 | { 48 | this.activity = activity; 49 | if (!path.exists()) path = Environment.getExternalStorageDirectory(); 50 | loadFileList(path); 51 | } 52 | 53 | /** 54 | * @return file dialog 55 | */ 56 | public Dialog createFileDialog() 57 | { 58 | Dialog dialog = null; 59 | AlertDialog.Builder builder = new AlertDialog.Builder(activity); 60 | 61 | builder.setTitle(currentPath.getPath()); 62 | if (selectDirectoryOption) 63 | { 64 | builder.setPositiveButton("Select directory", new DialogInterface.OnClickListener() 65 | { 66 | public void onClick(DialogInterface dialog, int which) 67 | { 68 | Log.d(TAG, currentPath.getPath()); 69 | fireDirectorySelectedEvent(currentPath); 70 | } 71 | }); 72 | } 73 | 74 | builder.setItems(fileList, new DialogInterface.OnClickListener() 75 | { 76 | public void onClick(DialogInterface dialog, int which) 77 | { 78 | String fileChosen = fileList[which]; 79 | File chosenFile = getChosenFile(fileChosen); 80 | if (chosenFile.isDirectory()) 81 | { 82 | loadFileList(chosenFile); 83 | dialog.cancel(); 84 | dialog.dismiss(); 85 | showDialog(); 86 | } else fireFileSelectedEvent(chosenFile); 87 | } 88 | }); 89 | 90 | dialog = builder.show(); 91 | return dialog; 92 | } 93 | 94 | 95 | public void addFileListener(FileSelectedListener listener) 96 | { 97 | fileListenerList.add(listener); 98 | } 99 | 100 | public void removeFileListener(FileSelectedListener listener) 101 | { 102 | fileListenerList.remove(listener); 103 | } 104 | 105 | public void setSelectDirectoryOption(boolean selectDirectoryOption) 106 | { 107 | this.selectDirectoryOption = selectDirectoryOption; 108 | } 109 | 110 | public void addDirectoryListener(DirectorySelectedListener listener) 111 | { 112 | dirListenerList.add(listener); 113 | } 114 | 115 | public void removeDirectoryListener(DirectorySelectedListener listener) 116 | { 117 | dirListenerList.remove(listener); 118 | } 119 | 120 | /** 121 | * Show file dialog 122 | */ 123 | public void showDialog() 124 | { 125 | createFileDialog().show(); 126 | } 127 | 128 | private void fireFileSelectedEvent(final File file) 129 | { 130 | fileListenerList.fireEvent(new ListenerList.FireHandler() 131 | { 132 | public void fireEvent(FileSelectedListener listener) 133 | { 134 | listener.fileSelected(file); 135 | } 136 | }); 137 | } 138 | 139 | private void fireDirectorySelectedEvent(final File directory) 140 | { 141 | dirListenerList.fireEvent(new ListenerList.FireHandler() 142 | { 143 | public void fireEvent(DirectorySelectedListener listener) 144 | { 145 | listener.directorySelected(directory); 146 | } 147 | }); 148 | } 149 | 150 | private void loadFileList(File path) 151 | { 152 | this.currentPath = path; 153 | List r = new ArrayList(); 154 | if (path.exists()) 155 | { 156 | if (path.getParentFile() != null) r.add(PARENT_DIR); 157 | FilenameFilter filter = new FilenameFilter() 158 | { 159 | public boolean accept(File dir, String filename) 160 | { 161 | File sel = new File(dir, filename); 162 | if (!sel.canRead()) return false; 163 | if (selectDirectoryOption) return sel.isDirectory(); 164 | else 165 | { 166 | boolean endsWith = false; 167 | if(fileEndsWith != null) 168 | { 169 | for (String ending : fileEndsWith) 170 | { 171 | if (filename.toLowerCase().endsWith(ending)) 172 | { 173 | endsWith = true; 174 | break; 175 | } 176 | } 177 | } 178 | return endsWith || sel.isDirectory(); 179 | } 180 | } 181 | }; 182 | String[] fileList1 = path.list(filter); 183 | for (String file : fileList1) 184 | { 185 | r.add(file); 186 | } 187 | } 188 | Collections.sort(r); 189 | fileList = (String[]) r.toArray(new String[]{}); 190 | } 191 | 192 | private File getChosenFile(String fileChosen) 193 | { 194 | if (fileChosen.equals(PARENT_DIR)) return currentPath.getParentFile(); 195 | else return new File(currentPath, fileChosen); 196 | } 197 | 198 | public void setFileEndsWith(String[] fileEndsWith) 199 | { 200 | if(fileEndsWith != null) 201 | { 202 | for(Integer i = 0; i < fileEndsWith.length; i++) 203 | { 204 | fileEndsWith[i] = fileEndsWith[i].toLowerCase(); 205 | } 206 | } 207 | this.fileEndsWith = fileEndsWith; 208 | 209 | // Again load file-list (because now file-list can change) 210 | loadFileList(currentPath); 211 | } 212 | } 213 | 214 | class ListenerList 215 | { 216 | private List listenerList = new ArrayList(); 217 | 218 | public interface FireHandler 219 | { 220 | void fireEvent(L listener); 221 | } 222 | 223 | public void add(L listener) 224 | { 225 | listenerList.add(listener); 226 | } 227 | 228 | public void fireEvent(FireHandler fireHandler) 229 | { 230 | List copy = new ArrayList(listenerList); 231 | for (L l : copy) 232 | { 233 | fireHandler.fireEvent(l); 234 | } 235 | } 236 | 237 | public void remove(L listener) 238 | { 239 | listenerList.remove(listener); 240 | } 241 | 242 | public List getListenerList() 243 | { 244 | return listenerList; 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/java/com/sidequest/launcher/gui/InfoOverlayDialog.java: -------------------------------------------------------------------------------- 1 | package com.sidequest.launcher.gui; 2 | 3 | import android.app.Dialog; 4 | import android.app.DialogFragment; 5 | import android.os.Bundle; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.TextView; 10 | 11 | import com.sidequest.launcher.R; 12 | 13 | /** 14 | * Info Overlay for additional information 15 | */ 16 | public class InfoOverlayDialog extends DialogFragment 17 | { 18 | /** 19 | * Create a new Info-Overlay dialog 20 | * @param title Title of the info dialog 21 | * @param summary Text of the info dialog 22 | * @return the dialog 23 | */ 24 | public static InfoOverlayDialog newInstance(String title, String summary) 25 | { 26 | // Create dialog and set custom style 27 | InfoOverlayDialog dialog = new InfoOverlayDialog(); 28 | dialog.setStyle(DialogFragment.STYLE_NO_FRAME, R.style.TransparentDialog); 29 | 30 | // Set title and summary 31 | dialog.setTitleAndSummary(title, summary); 32 | 33 | return dialog; 34 | } 35 | 36 | /** Title of the info dialog */ 37 | private String mTitle; 38 | 39 | /** Text of the info dialog */ 40 | private String mSummary; 41 | 42 | /** 43 | * Default constructor required for DialogFragment 44 | */ 45 | public InfoOverlayDialog() 46 | { 47 | } 48 | 49 | public void setTitleAndSummary(String title, String summary) 50 | { 51 | // Set title and summary 52 | mTitle = title; 53 | mSummary = summary; 54 | } 55 | 56 | @Override 57 | public Dialog onCreateDialog(Bundle savedInstanceState) 58 | { 59 | final Dialog dialog = super.onCreateDialog(savedInstanceState); 60 | dialog.getWindow().getAttributes().windowAnimations = R.style.DialogAnimation; 61 | return dialog; 62 | } 63 | 64 | @Override 65 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 66 | { 67 | // Create view 68 | View view = inflater.inflate(R.layout.infooverlaydialog, container); 69 | 70 | // Set text, icons and click-handler 71 | TextView title = (TextView) view.findViewById(R.id.title); 72 | title.setText(mTitle); 73 | 74 | TextView summary = (TextView) view.findViewById(R.id.summary); 75 | summary.setText(mSummary); 76 | 77 | return view; 78 | } 79 | } -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/java/com/sidequest/launcher/gui/InfosPrefActivity.java: -------------------------------------------------------------------------------- 1 | package com.sidequest.launcher.gui; 2 | 3 | import android.os.Bundle; 4 | import android.os.SystemClock; 5 | import android.preference.EditTextPreference; 6 | import android.preference.Preference; 7 | import android.preference.PreferenceFragment; 8 | import android.widget.Toast; 9 | 10 | import java.text.DateFormat; 11 | import java.util.Date; 12 | 13 | import com.sidequest.launcher.R; 14 | import com.sidequest.launcher.tools.Tools; 15 | 16 | /** 17 | * Info / System view 18 | */ 19 | public class InfosPrefActivity extends PreferenceFragment 20 | { 21 | static final long SLEEPTIME_MINIMUM = 1; 22 | static final long SLEEPTIME_MAXIMUM = 120; 23 | 24 | public InfosPrefActivity() 25 | { 26 | 27 | } 28 | 29 | @Override 30 | public void onCreate(Bundle savedInstanceState) 31 | { 32 | super.onCreate(savedInstanceState); 33 | 34 | addPreferencesFromResource(R.xml.infoprefactivity); 35 | 36 | Preference prefDeviceDetails = (Preference) findPreference("prefVirtualDeviceDetails"); 37 | prefDeviceDetails.setSummary(Tools.getDeviceDetails()); 38 | 39 | Preference prefHostname = (Preference) findPreference("prefVirtualHostname"); 40 | prefHostname.setSummary(Tools.getHostName(getActivity().getResources().getString(R.string.notfound))); 41 | 42 | Preference prefWifiName = (Preference) findPreference("prefVirtualWifiName"); 43 | prefWifiName.setSummary(Tools.getWifiSsid(this.getActivity(), getActivity().getResources().getString(R.string.notfound))); 44 | 45 | Preference prefIpAddress = (Preference) findPreference("prefVirtualIpAddress"); 46 | prefIpAddress.setSummary(Tools.getActiveIpAddress(getActivity(), getActivity().getResources().getString(R.string.notfound))); 47 | 48 | Preference prefDeviceUpTime = (Preference) findPreference("prefVirtualDeviceUpTime"); 49 | DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.MEDIUM, getResources().getConfiguration().locale); 50 | String upTime = String.format(getActivity().getResources().getString(R.string.uptimedesc), Tools.formatInterval(SystemClock.elapsedRealtime()), dateFormat.format(new Date(System.currentTimeMillis() - SystemClock.elapsedRealtime()))); 51 | prefDeviceUpTime.setSummary(upTime); 52 | 53 | // final EditTextPreference prefSetSleepTimeout = (EditTextPreference) findPreference("prefVirtualSleepTime"); 54 | // prefSetSleepTimeout.setText(((Long)(Tools.getSleepModeTimeout(getActivity()) / 1000 / 60)).toString()); 55 | // prefSetSleepTimeout.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() 56 | // { 57 | // @Override 58 | // public boolean onPreferenceChange(Preference preference, Object newValue) 59 | // { 60 | // long newTimeInMinutes = 0; 61 | // try 62 | // { 63 | // newTimeInMinutes = Long.valueOf(newValue.toString()); 64 | // } 65 | // catch (Exception ignore) 66 | // { 67 | // } 68 | // 69 | // do 70 | // { 71 | // if (newTimeInMinutes < SLEEPTIME_MINIMUM || newTimeInMinutes > SLEEPTIME_MAXIMUM) 72 | // { 73 | // Toast.makeText(InfosPrefActivity.this.getActivity(), String.format(getActivity().getResources().getString(R.string.sleeptime_limit), SLEEPTIME_MINIMUM, SLEEPTIME_MAXIMUM), Toast.LENGTH_SHORT).show(); 74 | // break; 75 | // } 76 | // 77 | // long newTimeInMs = newTimeInMinutes * 60 * 1000; 78 | // Tools.setSleepModeTimeout(getActivity(), newTimeInMs); 79 | // prefSetSleepTimeout.setText(((Long)(Tools.getSleepModeTimeout(getActivity()) / 1000 / 60)).toString()); 80 | // } 81 | // while (false); 82 | // 83 | // return false; 84 | // } 85 | // }); 86 | // 87 | // Preference prefGoToSleep = (Preference) findPreference("prefVirtualGoToSleep"); 88 | // prefGoToSleep.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() 89 | // { 90 | // @Override 91 | // public boolean onPreferenceClick(Preference preference) 92 | // { 93 | // Toast.makeText(InfosPrefActivity.this.getActivity(), getActivity().getResources().getString(R.string.gotosleep_summary), Toast.LENGTH_SHORT).show(); 94 | // return false; 95 | // } 96 | // }); 97 | // 98 | // Preference prefReboot = (Preference) findPreference("prefVirtualRestart"); 99 | // prefReboot.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() 100 | // { 101 | // @Override 102 | // public boolean onPreferenceClick(Preference preference) 103 | // { 104 | // Toast.makeText(InfosPrefActivity.this.getActivity(), getActivity().getResources().getString(R.string.system_restart_summary_removed), Toast.LENGTH_SHORT).show(); 105 | // return false; 106 | // } 107 | // }); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/java/com/sidequest/launcher/gui/LeftBarItemsListAdapter.java: -------------------------------------------------------------------------------- 1 | package com.sidequest.launcher.gui; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.BaseAdapter; 8 | import android.widget.TextView; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | import com.sidequest.launcher.R; 14 | 15 | /** 16 | * Adpater for items in the left selection bar 17 | */ 18 | public class LeftBarItemsListAdapter extends BaseAdapter 19 | { 20 | /** 21 | * A left bar fragment item 22 | */ 23 | public static class FragmentListItem 24 | { 25 | public String description; 26 | public String className; 27 | 28 | 29 | public FragmentListItem(String description, String className) 30 | { 31 | this.description = description; 32 | this.className = className; 33 | } 34 | 35 | @Override 36 | public String toString() 37 | { 38 | return description; 39 | } 40 | } 41 | 42 | /** Left bar item list */ 43 | private static List mItems = null; 44 | 45 | /** Current context */ 46 | private Context mContext; 47 | 48 | /** Create new adapter */ 49 | public LeftBarItemsListAdapter(Context context) 50 | { 51 | mContext = context; 52 | if(mItems == null) 53 | { 54 | mItems = new ArrayList(); 55 | mItems.add(new FragmentListItem(mContext.getResources().getString(R.string.leftbar_allapps), AppActivity.class.getName())); 56 | mItems.add(new FragmentListItem(mContext.getResources().getString(R.string.leftbar_infos), InfosPrefActivity.class.getName())); 57 | // mItems.add(new FragmentListItem(mContext.getResources().getString(R.string.leftbar_updates), UpdaterActivity.class.getName())); 58 | mItems.add(new FragmentListItem(mContext.getResources().getString(R.string.leftbar_settings), PreferenceActivity.class.getName())); 59 | } 60 | } 61 | 62 | /** 63 | * @return Count of installed apps 64 | */ 65 | public int getCount() 66 | { 67 | return mItems.size(); 68 | } 69 | 70 | /** 71 | * @param position Position of item to be returned 72 | * @return Item on position 73 | */ 74 | public FragmentListItem getItem(int position) 75 | { 76 | return mItems.get(position); 77 | } 78 | 79 | /** 80 | * Currently not used.. 81 | */ 82 | public long getItemId(int position) 83 | { 84 | return position; 85 | } 86 | 87 | /** 88 | * @return View of the given position 89 | */ 90 | public View getView(int position, View convertView, ViewGroup parent) 91 | { 92 | // Inflate layout 93 | LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 94 | View itemView; 95 | 96 | if (convertView == null) 97 | { 98 | // get layout from mobile.xml 99 | itemView = inflater.inflate(R.layout.leftbarlistitemlayout, parent, false); 100 | 101 | } else 102 | { 103 | itemView = (View) convertView; 104 | } 105 | 106 | // set value into textview 107 | TextView textView = (TextView) itemView.findViewById(R.id.textLabel); 108 | textView.setText(mItems.get(position).description); 109 | 110 | return itemView; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/java/com/sidequest/launcher/gui/PreferenceActivity.java: -------------------------------------------------------------------------------- 1 | package com.sidequest.launcher.gui; 2 | 3 | import android.content.SharedPreferences; 4 | import android.os.Bundle; 5 | import android.preference.EditTextPreference; 6 | import android.preference.ListPreference; 7 | import android.preference.MultiSelectListPreference; 8 | import android.preference.Preference; 9 | import android.preference.PreferenceFragment; 10 | import android.preference.PreferenceManager; 11 | import android.widget.Toast; 12 | 13 | import java.util.List; 14 | import java.util.Map; 15 | 16 | import com.sidequest.launcher.R; 17 | import com.sidequest.launcher.tools.AppInfo; 18 | import com.sidequest.launcher.tools.KodiUpdater; 19 | import com.sidequest.launcher.tools.SettingsProvider; 20 | import com.sidequest.launcher.tools.Tools; 21 | 22 | /** 23 | * Preferences activity 24 | */ 25 | public class PreferenceActivity extends PreferenceFragment 26 | { 27 | SettingsProvider mSettings = SettingsProvider.getInstance(this.getActivity()); 28 | 29 | SharedPreferences.OnSharedPreferenceChangeListener mSharedPreferenceListener = new SharedPreferences.OnSharedPreferenceChangeListener() 30 | { 31 | @Override 32 | public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) 33 | { 34 | Thread readValuesThread = new Thread(new Runnable() 35 | { 36 | @Override 37 | public void run() 38 | { 39 | mSettings.readValues(true); 40 | } 41 | }); 42 | readValuesThread.start(); 43 | } 44 | }; 45 | 46 | public PreferenceActivity() 47 | { 48 | 49 | } 50 | 51 | // @Override 52 | // public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 53 | // { 54 | // View rootView = super.onCreateView(inflater, container, savedInstanceState); 55 | // 56 | // // Set padding to settings view: 57 | // Integer pad = Math.round(getActivity().getResources().getDimension(R.dimen.settingspadding)); 58 | // Integer padBottom = Math.round(getActivity().getResources().getDimension(R.dimen.settingspadding_bottom)); 59 | // if (rootView != null) 60 | // { 61 | // rootView.setPadding(pad,pad,pad,padBottom); 62 | // } 63 | // 64 | // return rootView; 65 | // } 66 | 67 | @Override 68 | public void onCreate(Bundle savedInstanceState) 69 | { 70 | super.onCreate(savedInstanceState); 71 | 72 | addPreferencesFromResource(R.xml.preferencesactivity); 73 | 74 | InstalledAppsAdapter actAppsAdapter = new InstalledAppsAdapter(getActivity(), true, false); 75 | List actApps = actAppsAdapter.getAppList(); 76 | 77 | CharSequence[] entries = new CharSequence[actApps.size() + 1]; 78 | CharSequence[] entryValues = new CharSequence[actApps.size() + 1]; 79 | 80 | entries[0] = " - No Action - "; 81 | entryValues[0] = ""; 82 | 83 | for (Integer i = 1; i < actApps.size() + 1; i++) 84 | { 85 | AppInfo actApp = actApps.get(i - 1); 86 | entries[i] = actApp.getDisplayName(); 87 | entryValues[i] = actApp.packageName; 88 | } 89 | 90 | CharSequence[] langEntries = new CharSequence[SettingsProvider.LANG.size()]; 91 | CharSequence[] langValues = new CharSequence[SettingsProvider.LANG.size()]; 92 | Integer counter = 0; 93 | for (Map.Entry entry : SettingsProvider.LANG.entrySet()) 94 | { 95 | langEntries[counter] = entry.getValue(); 96 | langValues[counter] = entry.getKey(); 97 | counter++; 98 | } 99 | ListPreference languagePreference = (ListPreference) findPreference("prefLanguage"); 100 | languagePreference.setEntries(langEntries); 101 | languagePreference.setEntryValues(langValues); 102 | languagePreference.setDefaultValue(mSettings.getLanguage()); 103 | languagePreference.setValue(mSettings.getLanguage()); 104 | languagePreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() 105 | { 106 | @Override 107 | public boolean onPreferenceChange(Preference preference, Object newValue) 108 | { 109 | // Check if value has really changed: 110 | if (!mSettings.getLanguage().equals(newValue.toString())) 111 | { 112 | // Force reload settings 113 | mSettings.setLanguage(newValue.toString()); 114 | 115 | // Restart whole app 116 | Tools.doRestart(PreferenceActivity.this.getActivity()); 117 | } 118 | return true; 119 | } 120 | }); 121 | 122 | // ListPreference prefKodiUpdatePolicy = (ListPreference) findPreference("prefKodiUpdatePolicy"); 123 | // prefKodiUpdatePolicy.setEntries(KodiUpdater.UPDATE_POLICY.toArray(new CharSequence[KodiUpdater.UPDATE_POLICY.size()])); 124 | // prefKodiUpdatePolicy.setEntryValues(KodiUpdater.UPDATE_POLICY.toArray(new CharSequence[KodiUpdater.UPDATE_POLICY.size()])); 125 | // prefKodiUpdatePolicy.setDefaultValue(mSettings.getKodiUpdatePolicy()); 126 | // prefKodiUpdatePolicy.setValue(mSettings.getKodiUpdatePolicy()); 127 | 128 | InstalledAppsAdapter actHiddenAppsAdapter = new InstalledAppsAdapter(getActivity(), true, true); 129 | List actHiddenApps = actHiddenAppsAdapter.getAppList(); 130 | CharSequence[] hiddenEntries = new CharSequence[actHiddenApps.size()]; 131 | CharSequence[] hiddenEntryValues = new CharSequence[actHiddenApps.size()]; 132 | for (Integer i = 0; i < actHiddenApps.size(); i++) 133 | { 134 | AppInfo actApp = actHiddenApps.get(i); 135 | hiddenEntries[i] = actApp.getDisplayName(); 136 | hiddenEntryValues[i] = actApp.packageName; 137 | } 138 | 139 | MultiSelectListPreference hiddenAppsList = (MultiSelectListPreference) findPreference("prefHiddenApps"); 140 | hiddenAppsList.setEntries(hiddenEntries); 141 | hiddenAppsList.setEntryValues(hiddenEntryValues); 142 | hiddenAppsList.setDefaultValue(mSettings.getHiddenApps()); 143 | 144 | EditTextPreference appIconSize = (EditTextPreference) findPreference("prefAppIconSize"); 145 | appIconSize.setDefaultValue(mSettings.getAppIconSize().toString()); 146 | appIconSize.setText(mSettings.getAppIconSize().toString()); 147 | appIconSize.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() 148 | { 149 | @Override 150 | public boolean onPreferenceChange(Preference preference, Object newValue) 151 | { 152 | return mSettings.setAppIconSize(newValue, true); 153 | } 154 | }); 155 | 156 | Preference prefWallpaper = (Preference) findPreference("prefWallpaper"); 157 | prefWallpaper.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() 158 | { 159 | @Override 160 | public boolean onPreferenceClick(Preference preference) 161 | { 162 | WallpaperSelectDialog wallpaperSelector = new WallpaperSelectDialog((MainActivity) PreferenceActivity.this.getActivity()); 163 | wallpaperSelector.show(); 164 | return false; 165 | } 166 | }); 167 | 168 | Preference prefExportCurrentSettings = (Preference) findPreference("prefExportCurrentSettings"); 169 | prefExportCurrentSettings.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() 170 | { 171 | @Override 172 | public boolean onPreferenceClick(Preference preference) 173 | { 174 | Toast.makeText(getActivity(), Tools.settingsExport(getActivity()), Toast.LENGTH_SHORT).show(); 175 | return false; 176 | } 177 | }); 178 | 179 | Preference prefImportCurrentSettings = (Preference) findPreference("prefImportCurrentSettings"); 180 | prefImportCurrentSettings.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() 181 | { 182 | @Override 183 | public boolean onPreferenceClick(Preference preference) 184 | { 185 | String retVal = Tools.settingsImport(getActivity()); 186 | if (retVal == null) 187 | { 188 | Toast.makeText(getActivity(), "Settings imported successful, restart..", Toast.LENGTH_SHORT).show(); 189 | Thread restarter = new Thread(new Runnable() 190 | { 191 | @Override 192 | public void run() 193 | { 194 | try 195 | { 196 | Thread.sleep(2000); 197 | } 198 | catch (Exception ignore) 199 | { 200 | } 201 | 202 | Tools.doRestart(getActivity()); 203 | } 204 | }); 205 | restarter.start(); 206 | } else 207 | { 208 | Toast.makeText(getActivity(), retVal, Toast.LENGTH_SHORT).show(); 209 | } 210 | return false; 211 | } 212 | }); 213 | 214 | } 215 | 216 | 217 | @Override 218 | public void onPause() 219 | { 220 | super.onPause(); 221 | 222 | PreferenceManager.getDefaultSharedPreferences(getActivity()).unregisterOnSharedPreferenceChangeListener(mSharedPreferenceListener); 223 | 224 | // Force read-settings 225 | mSettings.readValues(true); 226 | } 227 | 228 | @Override 229 | public void onResume() 230 | { 231 | super.onResume(); 232 | 233 | PreferenceManager.getDefaultSharedPreferences(getActivity()).registerOnSharedPreferenceChangeListener(mSharedPreferenceListener); 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/java/com/sidequest/launcher/gui/ResizeWidthAnimation.java: -------------------------------------------------------------------------------- 1 | package com.sidequest.launcher.gui; 2 | 3 | import android.view.View; 4 | import android.view.animation.Animation; 5 | import android.view.animation.Transformation; 6 | 7 | /** 8 | * Animate change of width 9 | * https://stackoverflow.com/questions/16641539/animate-change-width-of-android-relativelayout 10 | */ 11 | public class ResizeWidthAnimation extends Animation 12 | { 13 | private int mWidth; 14 | private int mStartWidth; 15 | private View mView; 16 | 17 | public ResizeWidthAnimation(View view, int width) 18 | { 19 | mView = view; 20 | mWidth = width; 21 | mStartWidth = view.getWidth(); 22 | } 23 | 24 | @Override 25 | protected void applyTransformation(float interpolatedTime, Transformation t) 26 | { 27 | int newWidth = mStartWidth + (int) ((mWidth - mStartWidth) * interpolatedTime); 28 | 29 | mView.getLayoutParams().width = newWidth; 30 | mView.requestLayout(); 31 | } 32 | 33 | @Override 34 | public void initialize(int width, int height, int parentWidth, int parentHeight) 35 | { 36 | super.initialize(width, height, parentWidth, parentHeight); 37 | } 38 | 39 | @Override 40 | public boolean willChangeBounds() 41 | { 42 | return true; 43 | } 44 | } -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/java/com/sidequest/launcher/gui/UpdaterActivity.java: -------------------------------------------------------------------------------- 1 | package com.sidequest.launcher.gui; 2 | 3 | import android.app.Fragment; 4 | import android.os.Bundle; 5 | import android.util.Log; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.view.ViewTreeObserver; 10 | import android.widget.ListView; 11 | 12 | import java.io.PrintWriter; 13 | import java.io.StringWriter; 14 | 15 | import com.sidequest.launcher.R; 16 | import com.sidequest.launcher.tools.AppStarterUpdater; 17 | import com.sidequest.launcher.tools.SettingsProvider; 18 | import com.sidequest.launcher.tools.Updater; 19 | 20 | /** 21 | * Shows the updates for all available installable apps including AppStarter itself 22 | */ 23 | public class UpdaterActivity extends Fragment 24 | { 25 | /** Instance of settings provider */ 26 | private SettingsProvider mSettings = SettingsProvider.getInstance(getActivity()); 27 | 28 | /** ListView to show all updateable apps */ 29 | private ListView mListView; 30 | 31 | /** Indicates if update shall be triggered directly */ 32 | private Boolean mTriggerUpdate = false; 33 | 34 | /** Updater apps adapter */ 35 | UpdaterAppsAdapter mUpdaterAppsAdapter; 36 | 37 | /** Mandatory for fragment initation */ 38 | public UpdaterActivity(){ } 39 | 40 | @Override 41 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 42 | { 43 | View rootView = inflater.inflate(R.layout.updateractivity, container, false); 44 | 45 | // Get ListView 46 | mListView = (ListView) rootView.findViewById(R.id.listView); 47 | 48 | // Set updateable apps adapter 49 | mUpdaterAppsAdapter = new UpdaterAppsAdapter(this.getActivity()); 50 | mListView.setAdapter(mUpdaterAppsAdapter); 51 | 52 | // Make buttons useable 53 | mListView.setItemsCanFocus(true); 54 | mListView.setFocusable(false); 55 | mListView.setFocusableInTouchMode(false); 56 | mListView.setClickable(false); 57 | 58 | // Trigger update mechanism when first view is ready.. 59 | mListView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() 60 | { 61 | @Override 62 | public void onGlobalLayout() 63 | { 64 | try 65 | { 66 | // Remove listener 67 | mListView.getViewTreeObserver().removeOnGlobalLayoutListener(this); 68 | 69 | if(mTriggerUpdate) 70 | { 71 | mTriggerUpdate = false; 72 | 73 | Updater actAppStarterUpdater = (Updater) mUpdaterAppsAdapter.getItem(0); 74 | if(actAppStarterUpdater != null && actAppStarterUpdater instanceof AppStarterUpdater) 75 | { 76 | actAppStarterUpdater.DialogHandler.performUpdate(); 77 | } 78 | } 79 | } 80 | catch (Exception e) 81 | { 82 | StringWriter errors = new StringWriter(); 83 | e.printStackTrace(new PrintWriter(errors)); 84 | String errorReason = errors.toString(); 85 | Log.d(MainActivity.class.getName(), "Failed to trigger update directly: \n" + errorReason); 86 | } 87 | } 88 | }); 89 | 90 | return rootView; 91 | } 92 | 93 | /** Trigger update programmtically */ 94 | public void triggerUpdateOnStartup() 95 | { 96 | mTriggerUpdate = true; 97 | } 98 | 99 | @Override 100 | public void onCreate(Bundle savedInstanceState) 101 | { 102 | super.onCreate(savedInstanceState); 103 | } 104 | 105 | @Override 106 | public void onPause() 107 | { 108 | super.onPause(); 109 | } 110 | 111 | @Override 112 | public void onResume() 113 | { 114 | super.onResume(); 115 | mUpdaterAppsAdapter.notifyDataSetChanged(); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/java/com/sidequest/launcher/gui/UpdaterAppsAdapter.java: -------------------------------------------------------------------------------- 1 | package com.sidequest.launcher.gui; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.BaseAdapter; 9 | import android.widget.Button; 10 | import android.widget.TextView; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | import com.sidequest.launcher.R; 16 | import com.sidequest.launcher.tools.AppStarterUpdater; 17 | import com.sidequest.launcher.tools.KodiUpdater; 18 | import com.sidequest.launcher.tools.SPMCUpdater; 19 | import com.sidequest.launcher.tools.SettingsProvider; 20 | import com.sidequest.launcher.tools.Updater; 21 | 22 | /** 23 | * Adapter that lists all installed apps 24 | */ 25 | public class UpdaterAppsAdapter extends BaseAdapter 26 | { 27 | Activity mActivity; 28 | private List mUpdaterList; 29 | 30 | /** 31 | * Create new UpdaterAppsadapter 32 | */ 33 | public UpdaterAppsAdapter(Activity activity) 34 | { 35 | // Set context 36 | mActivity = activity; 37 | 38 | // Set list of updaters 39 | mUpdaterList = new ArrayList<>(); 40 | mUpdaterList.add(new AppStarterUpdater()); 41 | mUpdaterList.add(new KodiUpdater(activity)); 42 | mUpdaterList.add(new SPMCUpdater()); 43 | } 44 | 45 | /** 46 | * @return Count of installed apps 47 | */ 48 | public int getCount() 49 | { 50 | return mUpdaterList.size(); 51 | } 52 | 53 | /** 54 | * @param position Position of item to be returned 55 | * @return Item on position 56 | */ 57 | public Object getItem(int position) 58 | { 59 | return mUpdaterList.get(position); 60 | } 61 | 62 | /** 63 | * Currently not used.. 64 | */ 65 | public long getItemId(int position) 66 | { 67 | return position; 68 | } 69 | 70 | /** 71 | * @return View of the given position 72 | */ 73 | public View getView(int position, View convertView, ViewGroup parent) 74 | { 75 | // Get act updater 76 | final Updater actUpdater = mUpdaterList.get(position); 77 | 78 | // Inflate layout 79 | View rootView; 80 | 81 | if (convertView == null) 82 | { 83 | LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 84 | rootView = new View(mActivity); 85 | rootView = inflater.inflate(R.layout.appupdateritemlayout, parent, false); 86 | 87 | } 88 | else 89 | { 90 | rootView = (View) convertView; 91 | } 92 | 93 | // Set title 94 | TextView textViewTitle = (TextView) rootView.findViewById(R.id.title); 95 | textViewTitle.setText(actUpdater.getAppName()); 96 | 97 | // Set current version 98 | TextView textViewCurrentVersion = (TextView) rootView.findViewById(R.id.currentVersion); 99 | textViewCurrentVersion.setText(actUpdater.getCurrentVersion(mActivity)); 100 | 101 | // Set latest version 102 | final TextView textViewLatestVersion = (TextView) rootView.findViewById(R.id.latestVersion); 103 | String latestVersion = actUpdater.getLatestVersion(); 104 | if(latestVersion == null) 105 | { 106 | latestVersion = mActivity.getResources().getString(R.string.update_hitcheckfor); 107 | } 108 | textViewLatestVersion.setText(latestVersion); 109 | 110 | // Create an UpdaterDialogHandler 111 | final UpdaterDialogHandler updaterDialogHandler = new UpdaterDialogHandler(mActivity, actUpdater); 112 | actUpdater.DialogHandler = updaterDialogHandler; 113 | updaterDialogHandler.setCheckForUpdateFinishedListener(new Updater.OnCheckForUpdateFinishedListener() 114 | { 115 | @Override 116 | public void onCheckForUpdateFinished(String message) 117 | { 118 | if (actUpdater.getLatestVersion() != null) 119 | { 120 | if (actUpdater.isVersionNewer(actUpdater.getCurrentVersion(mActivity), actUpdater.getLatestVersion())) 121 | { 122 | textViewLatestVersion.setText(actUpdater.getLatestVersion() + " - " + mActivity.getResources().getString(R.string.update_foundnew)); 123 | 124 | if (actUpdater instanceof AppStarterUpdater) 125 | { 126 | AppActivity.LATEST_APP_VERSION = actUpdater.getLatestVersion(); 127 | } 128 | } else 129 | { 130 | textViewLatestVersion.setText(actUpdater.getLatestVersion() + " - " + mActivity.getResources().getString(R.string.update_foundnotnew)); 131 | } 132 | } else 133 | { 134 | textViewLatestVersion.setText(message); 135 | } 136 | } 137 | }); 138 | 139 | // Set the button onclicks 140 | Button checkUpdateButton = (Button) rootView.findViewById(R.id.buttonCheckForUpdate); 141 | checkUpdateButton.setOnClickListener(new View.OnClickListener() 142 | { 143 | @Override 144 | public void onClick(View v) 145 | { 146 | updaterDialogHandler.checkForUpdate(); 147 | } 148 | }); 149 | 150 | Button updateButton = (Button) rootView.findViewById(R.id.buttonUpdate); 151 | updateButton.setOnClickListener(new View.OnClickListener() 152 | { 153 | @Override 154 | public void onClick(View v) 155 | { 156 | updaterDialogHandler.performUpdate(); 157 | 158 | if(actUpdater instanceof AppStarterUpdater) 159 | { 160 | SettingsProvider settings = SettingsProvider.getInstance(mActivity); 161 | settings.setHaveUpdateSeen(false); 162 | } 163 | } 164 | }); 165 | 166 | if(rootView.getResources().getString(R.string.not_installed).equals(textViewCurrentVersion.getText())) 167 | { 168 | // App is not installed, change update to install text 169 | updateButton.setText(rootView.getResources().getString(R.string.install)); 170 | } 171 | 172 | return rootView; 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/java/com/sidequest/launcher/gui/UpdaterDialogHandler.java: -------------------------------------------------------------------------------- 1 | package com.sidequest.launcher.gui; 2 | 3 | import android.app.Activity; 4 | import android.app.ProgressDialog; 5 | 6 | import com.sidequest.launcher.R; 7 | import com.sidequest.launcher.tools.AppStarterUpdater; 8 | import com.sidequest.launcher.tools.Updater; 9 | 10 | /** 11 | * Handles the update-dialogs in case of an update 12 | */ 13 | public class UpdaterDialogHandler 14 | { 15 | /** Updater of the dialog handler */ 16 | private Updater mUpdater; 17 | 18 | /** Context of the current dialog handler */ 19 | private Activity mActivity; 20 | 21 | /** Check for update progress */ 22 | ProgressDialog mCheckForUpdateProgress = null; 23 | 24 | /** Update progress */ 25 | ProgressDialog mUpdateProgress = null; 26 | 27 | /** Listener for checkforupdate finished event */ 28 | Updater.OnCheckForUpdateFinishedListener mCheckForUpdateFinishedListener = null; 29 | 30 | public UpdaterDialogHandler(Activity activity, Updater updater) 31 | { 32 | mActivity = activity; 33 | mUpdater = updater; 34 | 35 | mUpdater.setOnCheckForUpdateFinishedListener(mOnCheckForUpdateFinishedListener); 36 | mUpdater.setOnUpdateProgressListener(mOnUpdateProgressListener); 37 | } 38 | 39 | public void setCheckForUpdateFinishedListener(Updater.OnCheckForUpdateFinishedListener listener) 40 | { 41 | mCheckForUpdateFinishedListener = listener; 42 | } 43 | 44 | public void checkForUpdate() 45 | { 46 | mCheckForUpdateProgress = ProgressDialog.show(mActivity, mActivity.getResources().getString(R.string.update_checkfortitle), mActivity.getResources().getString(R.string.update_checkfordesc), true); 47 | mUpdater.checkForUpdate(); 48 | } 49 | 50 | public void performUpdate() 51 | { 52 | mUpdateProgress = new ProgressDialog(mActivity); 53 | mUpdateProgress.setMessage(mActivity.getResources().getString(R.string.update_checkformessage)); 54 | mUpdateProgress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); 55 | mUpdateProgress.setCancelable(false); 56 | mUpdateProgress.setProgress(0); 57 | mUpdateProgress.show(); 58 | 59 | mUpdater.update(mActivity); 60 | } 61 | 62 | /** Handle check for update */ 63 | Updater.OnCheckForUpdateFinishedListener mOnCheckForUpdateFinishedListener = new AppStarterUpdater.OnCheckForUpdateFinishedListener() 64 | { 65 | @Override 66 | public void onCheckForUpdateFinished(final String message) 67 | { 68 | mActivity.runOnUiThread(new Runnable() 69 | { 70 | @Override 71 | public void run() 72 | { 73 | 74 | if (mCheckForUpdateProgress != null) 75 | { 76 | mCheckForUpdateProgress.dismiss(); 77 | mCheckForUpdateProgress = null; 78 | } 79 | mCheckForUpdateFinishedListener.onCheckForUpdateFinished(message); 80 | } 81 | }); 82 | } 83 | }; 84 | 85 | /** Handle update progress */ 86 | Updater.OnUpdateProgressListener mOnUpdateProgressListener = new AppStarterUpdater.OnUpdateProgressListener() 87 | { 88 | @Override 89 | public void onUpdateProgress(final Boolean isError,final Integer percent, final String message) 90 | { 91 | mActivity.runOnUiThread(new Runnable() 92 | { 93 | @Override 94 | public void run() 95 | { 96 | if (isError) 97 | { 98 | mUpdateProgress.setProgress(100); 99 | mUpdateProgress.setMessage(message); 100 | mUpdateProgress.setCancelable(true); 101 | } else 102 | { 103 | mUpdateProgress.setProgress(percent); 104 | mUpdateProgress.setMessage(message); 105 | if (percent >= 100) 106 | { 107 | mUpdateProgress.setCancelable(true); 108 | mUpdateProgress.dismiss(); 109 | } 110 | } 111 | } 112 | }); 113 | } 114 | }; 115 | 116 | } 117 | -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/java/com/sidequest/launcher/gui/WallpaperSelectDialog.java: -------------------------------------------------------------------------------- 1 | package com.sidequest.launcher.gui; 2 | 3 | import android.app.AlertDialog; 4 | import android.app.Dialog; 5 | import android.content.DialogInterface; 6 | import android.graphics.Bitmap; 7 | import android.graphics.BitmapFactory; 8 | import android.graphics.drawable.BitmapDrawable; 9 | import android.os.Environment; 10 | import android.util.Log; 11 | import android.widget.Toast; 12 | 13 | import java.io.File; 14 | import java.io.FileOutputStream; 15 | import java.io.PrintWriter; 16 | import java.io.StringWriter; 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | import com.sidequest.launcher.R; 21 | import com.sidequest.launcher.tools.Tools; 22 | 23 | /** 24 | * Created by luki on 28.06.15. 25 | */ 26 | public class WallpaperSelectDialog 27 | { 28 | /** Current MainActivity */ 29 | MainActivity mMainActivity; 30 | 31 | /** Current Wallpaper Path */ 32 | File mWallpaperPath; 33 | 34 | public WallpaperSelectDialog(MainActivity mainActivity) 35 | { 36 | mMainActivity = mainActivity; 37 | mWallpaperPath = new File(mMainActivity.getApplicationInfo().dataDir, "wallpaper.png"); 38 | } 39 | 40 | public void setWallpaper(Boolean forceError) 41 | { 42 | try 43 | { 44 | if(!forceError) 45 | { 46 | if(!mWallpaperPath.exists()) 47 | { 48 | return; 49 | } 50 | } 51 | BitmapFactory.Options bmOptions = new BitmapFactory.Options(); 52 | Bitmap bitmap = BitmapFactory.decodeFile(mWallpaperPath.getAbsolutePath(), bmOptions); 53 | 54 | BitmapDrawable drawable = new BitmapDrawable(mMainActivity.getResources(), bitmap); 55 | mMainActivity.setBackgroundImage(drawable); 56 | } 57 | catch(Exception e) 58 | { 59 | Toast.makeText(mMainActivity, "Could not set wallpaper", Toast.LENGTH_SHORT).show(); 60 | StringWriter errors = new StringWriter(); 61 | e.printStackTrace(new PrintWriter(errors)); 62 | String errorReason = errors.toString(); 63 | Log.d(WallpaperSelectDialog.class.getName(), "Failed to set background: \n" + errorReason); 64 | } 65 | } 66 | 67 | public void show() 68 | { 69 | AlertDialog.Builder builder = new AlertDialog.Builder(mMainActivity); 70 | 71 | builder.setTitle("JPG/PNG - 1920x1080px"); 72 | 73 | List items = new ArrayList(); 74 | if(mWallpaperPath.exists()) 75 | { 76 | items.add(mMainActivity.getResources().getString(R.string.remove_wallpaper)); 77 | } 78 | items.add(mMainActivity.getResources().getString(R.string.select_wallpaper)); 79 | 80 | final String[] itemList = items.toArray(new String[items.size()]); 81 | 82 | builder.setItems(itemList, new DialogInterface.OnClickListener() 83 | { 84 | public void onClick(DialogInterface dialog, int which) 85 | { 86 | dialog.cancel(); 87 | dialog.dismiss(); 88 | 89 | String itemChosen = itemList[which]; 90 | if (itemChosen == mMainActivity.getResources().getString(R.string.remove_wallpaper)) 91 | { 92 | deleteWallpaper(); 93 | } 94 | else if(itemChosen == mMainActivity.getResources().getString(R.string.select_wallpaper)) 95 | { 96 | showFileSelectorDialog(); 97 | } 98 | } 99 | }); 100 | 101 | Dialog dialog = builder.show(); 102 | dialog.show(); 103 | } 104 | 105 | private void deleteWallpaper() 106 | { 107 | if(mWallpaperPath.exists()) 108 | { 109 | mWallpaperPath.delete(); 110 | Tools.doRestart(mMainActivity); 111 | } 112 | } 113 | 114 | private void showFileSelectorDialog() 115 | { 116 | File mPath = Environment.getExternalStorageDirectory(); 117 | FileDialog fileDialog = new FileDialog(mMainActivity, mPath); 118 | fileDialog.setFileEndsWith(new String[]{".jpg", ".jpeg", ".png"}); 119 | fileDialog.addFileListener(new FileDialog.FileSelectedListener() 120 | { 121 | public void fileSelected(File file) 122 | { 123 | WallpaperSelectDialog.this.handleFileSelected(file); 124 | } 125 | }); 126 | //fileDialog.addDirectoryListener(new FileDialog.DirectorySelectedListener() { 127 | // public void directorySelected(File directory) { 128 | // Log.d(getClass().getName(), "selected dir " + directory.toString()); 129 | // } 130 | //}); 131 | //fileDialog.setSelectDirectoryOption(false); 132 | fileDialog.showDialog(); 133 | } 134 | 135 | private void handleFileSelected(File file) 136 | { 137 | // Now we try to resize and set this file 138 | try 139 | { 140 | BitmapFactory.Options bmOptions = new BitmapFactory.Options(); 141 | Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath(), bmOptions); 142 | 143 | // Resize image 144 | bitmap = Tools.resizeBitmapToFit(bitmap, mMainActivity.getBackgroundWidth(), mMainActivity.getBackgroundHeight()); 145 | 146 | File dir = mWallpaperPath.getParentFile(); 147 | if(!dir.exists()) 148 | { 149 | dir.mkdirs(); 150 | } 151 | if(mWallpaperPath.exists()) 152 | { 153 | mWallpaperPath.delete(); 154 | } 155 | 156 | FileOutputStream fOut = new FileOutputStream(mWallpaperPath); 157 | 158 | bitmap.compress(Bitmap.CompressFormat.PNG, 90, fOut); 159 | fOut.flush(); 160 | fOut.close(); 161 | 162 | // Now try to load this one 163 | setWallpaper(true); 164 | } 165 | catch(Exception e) 166 | { 167 | StringWriter errors = new StringWriter(); 168 | e.printStackTrace(new PrintWriter(errors)); 169 | String errorReason = errors.toString(); 170 | Log.d(MainActivity.class.getName(), "Failed to set background: \n" + errorReason); 171 | } 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/java/com/sidequest/launcher/tools/AppInfo.java: -------------------------------------------------------------------------------- 1 | package com.sidequest.launcher.tools; 2 | 3 | import android.content.Context; 4 | import android.content.pm.ApplicationInfo; 5 | import android.graphics.drawable.Drawable; 6 | 7 | /** 8 | * Container to hold app informations 9 | */ 10 | public class AppInfo extends ApplicationInfo 11 | { 12 | /** The current context */ 13 | Context mContext; 14 | 15 | /** 16 | * @param app App to be hold 17 | */ 18 | public AppInfo(Context context, ApplicationInfo app) 19 | { 20 | super(app); 21 | mContext = context; 22 | } 23 | 24 | /** 25 | * @return Name to be displayed 26 | */ 27 | public String getDisplayName() 28 | { 29 | String retVal = this.loadLabel(mContext.getPackageManager()).toString(); 30 | if(retVal == null || retVal.equals("")) 31 | { 32 | retVal = packageName; 33 | } 34 | return retVal; 35 | } 36 | 37 | /** 38 | * @return Icon to be displayed 39 | */ 40 | public Drawable getDisplayIcon() 41 | { 42 | return this.loadIcon(mContext.getPackageManager()); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/java/com/sidequest/launcher/tools/AppStarter.java: -------------------------------------------------------------------------------- 1 | package com.sidequest.launcher.tools; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.content.pm.PackageManager; 7 | import android.content.pm.ResolveInfo; 8 | import android.net.Uri; 9 | import android.provider.Settings; 10 | import android.util.Log; 11 | 12 | import java.io.PrintWriter; 13 | import java.io.StringWriter; 14 | 15 | import com.sidequest.launcher.gui.InstalledAppsAdapter; 16 | 17 | /** 18 | * Provides methods to start apps 19 | */ 20 | public class AppStarter 21 | { 22 | /** Name of the launcher package */ 23 | private static String mLauncherPackageName = null; 24 | 25 | /** Thread to start and watch if correct action is happening */ 26 | private static Thread mStartAndWatchThread = null; 27 | 28 | private static Object mSyncObj = new Object(); 29 | 30 | public static void stopWatchThread() 31 | { 32 | synchronized (mSyncObj) 33 | { 34 | Log.d(AppStarter.class.getName(), "Stop watch thread"); 35 | try 36 | { 37 | if(mStartAndWatchThread != null && mStartAndWatchThread.isAlive()) 38 | { 39 | mStartAndWatchThread.interrupt(); 40 | mStartAndWatchThread.join(); 41 | mStartAndWatchThread = null; 42 | Log.d(AppStarter.class.getName(), "Watchthread stopped"); 43 | } 44 | else 45 | { 46 | Log.d(AppStarter.class.getName(), "Watchthread was not alive, nothing to be done."); 47 | } 48 | } 49 | catch(Exception e) 50 | { 51 | Log.d(AppStarter.class.getName(), "Exception while stopping watchthread: \n" + e.getMessage()); 52 | } 53 | } 54 | } 55 | 56 | /** 57 | * Starting an app by its package-name 58 | * @param context Context in that the app shall be started. 59 | * @param packageName Name of the apps package 60 | * @param isClickAction Indicates if this method is initiated by a click-action 61 | */ 62 | public static void startAppByPackageName(final Activity context, String packageName, Boolean isClickAction, Boolean isStartupAction, Boolean isClearPreviousInstancesForced) 63 | { 64 | try 65 | { 66 | // If currently a watchdog thread is running, stop it first 67 | stopWatchThread(); 68 | 69 | synchronized (mSyncObj) 70 | { 71 | if (packageName != null && !packageName.equals("")) 72 | { 73 | // Prepare the intent 74 | final Intent launchIntent = InstalledAppsAdapter.getLaunchableIntentByPackageName(context, packageName); 75 | if (isStartupAction || isClearPreviousInstancesForced) 76 | { 77 | // Start in new Task if startup -> perhaps prevents weird colors of kodi 78 | // that some users reported.. 79 | Log.d(AppStarter.class.getName(), "Using FLAG_ACTIVITY_CLEAR_TASK: isStartupAction=" + isStartupAction.toString() + ", isClearPreviousInstancesForced=" + isClearPreviousInstancesForced.toString()); 80 | launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 81 | launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); 82 | } 83 | 84 | // Launch the intent 85 | Log.d(AppStarter.class.getName(), "Starting launcher activity of package: " + packageName); 86 | context.getApplication().startActivity(launchIntent); 87 | } 88 | } 89 | } 90 | catch(Exception e) 91 | { 92 | StringWriter errors = new StringWriter(); 93 | e.printStackTrace(new PrintWriter(errors)); 94 | String errorReason = errors.toString(); 95 | Log.d(AppStarter.class.getName(), "Failed to launch activity: \n" + errorReason); 96 | } 97 | } 98 | 99 | /** 100 | * Start settings view by packagename 101 | * @param context 102 | * @param packageName 103 | */ 104 | public static void startSettingsViewByPackageName(Context context, String packageName) 105 | { 106 | try 107 | { 108 | Intent intent = new Intent(); 109 | intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); 110 | intent.setData(Uri.fromParts("package", packageName, null)); 111 | 112 | context.startActivity(intent); 113 | } 114 | catch(Exception e) 115 | { 116 | StringWriter errors = new StringWriter(); 117 | e.printStackTrace(new PrintWriter(errors)); 118 | String errorReason = errors.toString(); 119 | Log.d(AppStarter.class.getName(), "Failed to launch settings-activity: \n" + errorReason); 120 | } 121 | } 122 | 123 | /** 124 | * Uses package manager to find the package name of the device launcher. Usually this package 125 | * is "com.android.launcher" but can be different at times. This is a generic solution which 126 | * works on all platforms.` 127 | */ 128 | public static synchronized String getLauncherPackageName(Context context) 129 | { 130 | // We only need to find the launcher package once as it should not change 131 | if(mLauncherPackageName == null) 132 | { 133 | // Create launcher Intent 134 | final Intent intent = new Intent(Intent.ACTION_MAIN); 135 | intent.addCategory(Intent.CATEGORY_HOME); 136 | 137 | // Use PackageManager to get the launcher package name 138 | PackageManager pm = context.getPackageManager(); 139 | ResolveInfo resolveInfo = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY); 140 | mLauncherPackageName = resolveInfo.activityInfo.packageName; 141 | } 142 | 143 | return mLauncherPackageName; 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/java/com/sidequest/launcher/tools/AppStarterUpdater.java: -------------------------------------------------------------------------------- 1 | package com.sidequest.launcher.tools; 2 | 3 | import android.content.Context; 4 | 5 | import org.json.JSONArray; 6 | import org.json.JSONException; 7 | import org.json.JSONObject; 8 | 9 | import java.net.URL; 10 | import java.util.Scanner; 11 | 12 | /** 13 | * Update class for AppStarter 14 | */ 15 | public class AppStarterUpdater extends Updater 16 | { 17 | /** Update URL where updated versions are found */ 18 | private String mUpdateUrl = "https://api.github.com/repos/sphinx02/AppStarter/releases"; 19 | 20 | @Override 21 | public String getAppName() 22 | { 23 | return "AppStarter"; 24 | } 25 | 26 | @Override 27 | public String getPackageName(Context context) 28 | { 29 | return context.getApplicationInfo().packageName; 30 | } 31 | 32 | @Override 33 | public Boolean isVersionNewer(String oldVersion, String newVersion) 34 | { 35 | // Use standard check 36 | return isVersionNewerStandardCheck(oldVersion, newVersion); 37 | } 38 | 39 | @Override 40 | protected void updateLatestVersionAndApkDownloadUrl() throws Exception 41 | { 42 | // Build the url 43 | URL url = new URL(mUpdateUrl); 44 | 45 | // Read from the URL 46 | Scanner scan = new Scanner(url.openStream()); 47 | StringBuilder str = new StringBuilder(); 48 | while (scan.hasNext()) 49 | { 50 | str.append(scan.nextLine()); 51 | } 52 | scan.close(); 53 | 54 | // build a JSON object 55 | JSONArray obj = new JSONArray(str.toString()); 56 | if(obj.length() <= 0) 57 | { 58 | throw new JSONException("No content found"); 59 | } 60 | 61 | JSONObject latestRelease = obj.getJSONObject(0); 62 | String tagName = latestRelease.getString("tag_name"); 63 | if(tagName == null || tagName.equals("")) 64 | { 65 | throw new JSONException("Latest release tag name is empty"); 66 | } 67 | mLatestVersion = tagName; 68 | 69 | // Search for apk-download url 70 | JSONArray assets = latestRelease.getJSONArray("assets"); 71 | for(Integer i = 0; i < assets.length(); i++) 72 | { 73 | JSONObject currentAsset = assets.getJSONObject(i); 74 | String downloadUrl = currentAsset.getString("browser_download_url"); 75 | if(downloadUrl.startsWith("https://github.com/sphinx02/") && downloadUrl.endsWith(".apk")) 76 | { 77 | mApkDownloadUrl = downloadUrl; 78 | break; 79 | } 80 | } 81 | if(mApkDownloadUrl == null) 82 | { 83 | throw new JSONException("No .apk download URL found"); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/java/com/sidequest/launcher/tools/KodiUpdater.java: -------------------------------------------------------------------------------- 1 | package com.sidequest.launcher.tools; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | 6 | import org.jsoup.Jsoup; 7 | import org.jsoup.nodes.Document; 8 | import org.jsoup.select.Elements; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | public class KodiUpdater extends Updater 14 | { 15 | public static List UPDATE_POLICY = new ArrayList() 16 | { 17 | { 18 | add("Stable"); 19 | add("Beta and RC"); 20 | add("Nightly Builds"); 21 | } 22 | }; 23 | 24 | /** Update URL where updated versions are found */ 25 | private String mUpdateUrl = "http://mirrors.kodi.tv/releases/android/arm/"; 26 | 27 | /** Update URL for nightly versions */ 28 | private String mUpdateUrlNightly = "http://mirrors.kodi.tv/nightlies/android/arm/"; 29 | 30 | /** Current context */ 31 | private Context mContext; 32 | 33 | /** Instance of settings */ 34 | private SettingsProvider mSettings; 35 | 36 | /** Constructor to get Context */ 37 | public KodiUpdater(Context context) 38 | { 39 | mContext = context; 40 | mSettings = SettingsProvider.getInstance(context); 41 | } 42 | 43 | @Override 44 | public String getAppName() 45 | { 46 | return "Kodi"; 47 | } 48 | 49 | @Override 50 | public String getPackageName(Context context) 51 | { 52 | return "org.xbmc.kodi"; 53 | } 54 | 55 | @Override 56 | public Boolean isVersionNewer(String oldVersion, String newVersion) 57 | { 58 | // // Kodi versiong String can have additional RC-Version which is lower 59 | // // than equal version String without RC-Version 60 | // Boolean retVal = false; 61 | // 62 | // // Start do-while-false to be able to break out any time 63 | // do 64 | // { 65 | // // First prepare Strings 66 | // String workOldVersion = oldVersion.replace("_", "-").toUpperCase(); 67 | // String workNewVersion = newVersion.replace("_", "-").toUpperCase(); 68 | // 69 | // // If Strings are now equal, version is not newer 70 | // if(workOldVersion.equals(workNewVersion)) 71 | // { 72 | // retVal = false; 73 | // break; 74 | // } 75 | // 76 | // // Split version Strings 77 | // String[] splitOldVersion = workOldVersion.split("-"); 78 | // String[] splitNewVersion = workNewVersion.split("-"); 79 | // 80 | // // We should have at least one version string 81 | // if(splitOldVersion.length < 1 || splitNewVersion.length < 1) 82 | // { 83 | // retVal = false; 84 | // break; 85 | // } 86 | // 87 | // // If the first part (the normal version string) is identical 88 | // // we have to perform further tests 89 | // if(splitOldVersion[0].equals(splitNewVersion[0])) 90 | // { 91 | // // If only the oldversion string has the rc-part, 92 | // // the version is newer as no rc-part is newer than any rc-part 93 | // if(splitOldVersion.length == 2 && splitNewVersion.length == 1) 94 | // { 95 | // retVal = true; 96 | // break; 97 | // } 98 | // 99 | // // If both have the rc-part, we have to compare the rc part 100 | // if(splitOldVersion.length == 2 && splitNewVersion.length == 2) 101 | // { 102 | // try 103 | // { 104 | // String oldRc = splitOldVersion[1]; 105 | // String newRc = splitNewVersion[1]; 106 | // 107 | // if(oldRc.startsWith("RC") && newRc.startsWith("RC")) 108 | // { 109 | // oldRc = oldRc.substring(2, oldRc.length()); 110 | // newRc = newRc.substring(2, newRc.length()); 111 | // Integer oldInt = Integer.valueOf(oldRc); 112 | // Integer newInt = Integer.valueOf(newRc); 113 | // if(newInt > oldInt) 114 | // { 115 | // retVal = true; 116 | // break; 117 | // } 118 | // } 119 | // else if(oldRc.startsWith("BETA") && newRc.startsWith("RC")) 120 | // { 121 | // retVal = true; 122 | // } 123 | // } 124 | // catch(Exception ignore){} 125 | // break; 126 | // } 127 | // } 128 | // 129 | // // Else we use the standard check for the main-version part 130 | // retVal = isVersionNewerStandardCheck(splitOldVersion[0], splitNewVersion[0]); 131 | // 132 | // } 133 | // while(false); 134 | 135 | // Too complex, we simply check if the versions are equal or not 136 | Boolean retVal = false; 137 | String workOldVersion = oldVersion.replace("_", "-").toUpperCase(); 138 | String workNewVersion = newVersion.replace("_", "-").toUpperCase(); 139 | if(!workOldVersion.equals(workNewVersion)) 140 | { 141 | retVal = true; 142 | } 143 | 144 | return retVal; 145 | } 146 | 147 | @Override 148 | protected void updateLatestVersionAndApkDownloadUrl() throws Exception 149 | { 150 | String updatePolicy = mSettings.getKodiUpdatePolicy(); 151 | String updateUrl = mUpdateUrl; 152 | Log.d("KODI-UPDATER", "Policy: " + updatePolicy); 153 | 154 | if(updatePolicy.equals(UPDATE_POLICY.get(2))) 155 | { 156 | // Change link to nightlies 157 | updateUrl = mUpdateUrlNightly; 158 | } 159 | 160 | Document doc = Jsoup.connect(updateUrl).get(); 161 | Elements files = doc.select("#list tbody tr"); 162 | String latestApk = ""; 163 | for(int i = 0; i < files.size(); i++) 164 | { 165 | String foundApk = files.get(i).select("td").first().text(); 166 | Log.d("KODI-UPDATER", "Found: " + foundApk); 167 | if(foundApk.toLowerCase().endsWith(".apk")) 168 | { 169 | if(updatePolicy.equals(UPDATE_POLICY.get(1)) || updatePolicy.equals(UPDATE_POLICY.get(2))) 170 | { 171 | // We use the first file with .apk ending 172 | latestApk = foundApk; 173 | break; 174 | } 175 | else 176 | { 177 | // We have to check if this is no RC, ALPHA, OR BETA 178 | String replacedApkName = foundApk.replace("_", "-").toUpperCase(); 179 | String[] splitApkName = replacedApkName.split("-"); 180 | if(splitApkName.length < 4 || (!splitApkName[3].startsWith("RC") && !splitApkName[3].startsWith("BETA") && !splitApkName[3].startsWith("ALPHA"))) 181 | { 182 | latestApk = foundApk; 183 | break; 184 | } 185 | } 186 | } 187 | } 188 | if(latestApk.equals("")) 189 | { 190 | throw new Exception("No apk found on: " + mUpdateUrl); 191 | } 192 | 193 | mApkDownloadUrl = updateUrl + latestApk; 194 | mLatestVersion = getVersion(latestApk); 195 | } 196 | 197 | /** 198 | * Get version from file name 199 | * @param apkName file name to be parsedf 200 | * @return Version string 201 | */ 202 | private static String getVersion(String apkName) 203 | { 204 | String retVal = null; 205 | 206 | try 207 | { 208 | if(apkName != null && !apkName.equals("")) 209 | { 210 | // apkName = apkName 211 | // .replace("kodi-", "") 212 | // .replace("-Isengard", "") 213 | // .replace("-Jarvis", "") 214 | // .replace("_rc", "-RC") 215 | // .replace("_alpha", "-ALPHA") 216 | // .replace("-armeabi-v7a.apk", ""); 217 | // retVal = "v" + apkName; 218 | 219 | // We try to split up the kodi apk name into parts 220 | // and check the correct parts 221 | String replacedApkName = apkName.replace("_", "-").toUpperCase(); 222 | String[] splitApkName = replacedApkName.split("-"); 223 | if(splitApkName.length >= 2) 224 | { 225 | retVal = "v" + splitApkName[1]; 226 | } 227 | if(splitApkName.length >= 4 && splitApkName[3].startsWith("RC") || splitApkName[3].startsWith("BETA") || splitApkName[3].startsWith("ALPHA")) 228 | { 229 | retVal += "-" + splitApkName[3]; 230 | } 231 | } 232 | } 233 | catch(Exception ignore) { } 234 | 235 | return retVal; 236 | } 237 | } 238 | -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/java/com/sidequest/launcher/tools/SPMCUpdater.java: -------------------------------------------------------------------------------- 1 | package com.sidequest.launcher.tools; 2 | 3 | import android.content.Context; 4 | 5 | import org.json.JSONArray; 6 | import org.json.JSONException; 7 | import org.json.JSONObject; 8 | 9 | import java.net.URL; 10 | import java.util.Scanner; 11 | 12 | /** 13 | * Handles updates for SPMC 14 | */ 15 | public class SPMCUpdater extends Updater 16 | { 17 | /** Update URL where updated versions are found */ 18 | private String mUpdateUrl = "https://api.github.com/repos/koying/SPMC/releases"; 19 | 20 | @Override 21 | public String getAppName() 22 | { 23 | return "SPMC"; 24 | } 25 | 26 | @Override 27 | public String getPackageName(Context context) 28 | { 29 | return "com.semperpax.spmc16"; 30 | } 31 | 32 | @Override 33 | public Boolean isVersionNewer(String oldVersion, String newVersion) 34 | { 35 | // Use standard check 36 | return isVersionNewerStandardCheck(oldVersion, newVersion); 37 | } 38 | 39 | @Override 40 | public String getCurrentVersion(Context context) 41 | { 42 | return Tools.getCurrentAppVersion(context, getPackageName(context)).replace("-", "."); 43 | } 44 | 45 | @Override 46 | protected void updateLatestVersionAndApkDownloadUrl() throws Exception 47 | { 48 | // Build the url 49 | URL url = new URL(mUpdateUrl); 50 | 51 | // Read from the URL 52 | Scanner scan = new Scanner(url.openStream()); 53 | StringBuilder str = new StringBuilder(); 54 | while (scan.hasNext()) 55 | { 56 | str.append(scan.nextLine()); 57 | } 58 | scan.close(); 59 | 60 | // build a JSON object 61 | JSONArray obj = new JSONArray(str.toString()); 62 | if(obj.length() <= 0) 63 | { 64 | throw new JSONException("No content found"); 65 | } 66 | 67 | JSONObject latestRelease = obj.getJSONObject(0); 68 | String tagName = latestRelease.getString("tag_name"); 69 | if(tagName == null || tagName.equals("")) 70 | { 71 | throw new JSONException("Latest release tag name is empty"); 72 | } 73 | mLatestVersion = "v" + tagName.replaceAll("[^\\d.]", ""); 74 | 75 | // Search for apk-download url 76 | JSONArray assets = latestRelease.getJSONArray("assets"); 77 | for(Integer i = 0; i < assets.length(); i++) 78 | { 79 | JSONObject currentAsset = assets.getJSONObject(i); 80 | String downloadUrl = currentAsset.getString("browser_download_url"); 81 | if(downloadUrl.startsWith("https://github.com/koying/SPMC/releases") 82 | && downloadUrl.endsWith(".apk") 83 | && downloadUrl.toLowerCase().contains("arm") 84 | && !(downloadUrl.toLowerCase().contains("launcher"))) 85 | { 86 | mApkDownloadUrl = downloadUrl; 87 | break; 88 | } 89 | } 90 | if(mApkDownloadUrl == null) 91 | { 92 | throw new JSONException("No .apk download URL found"); 93 | } 94 | } 95 | } 96 | 97 | -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/java/com/sidequest/launcher/tools/ZipDirectory.java: -------------------------------------------------------------------------------- 1 | package com.sidequest.launcher.tools; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileNotFoundException; 6 | import java.io.FileOutputStream; 7 | import java.io.IOException; 8 | import java.io.OutputStream; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | import java.util.zip.ZipEntry; 12 | import java.util.zip.ZipInputStream; 13 | import java.util.zip.ZipOutputStream; 14 | 15 | public class ZipDirectory 16 | { 17 | 18 | public static void zipDirectory(String directoryPath, String zipFileNamePath) throws IOException 19 | { 20 | File directoryToZip = new File(directoryPath); 21 | File zipFile = new File(zipFileNamePath); 22 | File zipFilePath = zipFile.getParentFile(); 23 | if (!zipFilePath.exists()) 24 | { 25 | zipFilePath.mkdirs(); 26 | } 27 | if (zipFile.exists()) 28 | { 29 | zipFile.delete(); 30 | } 31 | 32 | List fileList = new ArrayList(); 33 | getAllFiles(directoryToZip, fileList); 34 | writeZipFile(directoryToZip, fileList, zipFile); 35 | } 36 | 37 | 38 | 39 | /** 40 | * Extract a zip file to the given destination folder. 41 | * @param file zip file to extract 42 | * @param destination destinatin folder 43 | */ 44 | public static void unZipDirectory(File file, File destination) throws IOException 45 | { 46 | ZipInputStream in = null; 47 | OutputStream out = null; 48 | try 49 | { 50 | // Open the ZIP file 51 | in = new ZipInputStream(new FileInputStream(file)); 52 | 53 | ZipEntry entry = null; 54 | while ((entry = in.getNextEntry()) != null) 55 | { 56 | String outFilename = entry.getName(); 57 | 58 | // Open the output file 59 | if (entry.isDirectory()) 60 | { 61 | new File(destination, outFilename).mkdirs(); 62 | } 63 | else 64 | { 65 | File outputFile = new File(destination, outFilename); 66 | File outputFileFolder = outputFile.getParentFile(); 67 | if(!outputFileFolder.exists()) 68 | { 69 | outputFileFolder.mkdirs(); 70 | } 71 | if(outputFile.exists()) 72 | { 73 | outputFile.delete(); 74 | } 75 | out = new FileOutputStream(outputFile); 76 | 77 | // Transfer bytes from the ZIP file to the output file 78 | byte[] buf = new byte[1024]; 79 | int len; 80 | 81 | while ((len = in.read(buf)) > 0) 82 | { 83 | out.write(buf, 0, len); 84 | } 85 | 86 | // Close the stream 87 | out.close(); 88 | } 89 | } 90 | } 91 | finally 92 | { 93 | // Close the stream 94 | if (in != null) 95 | { 96 | in.close(); 97 | } 98 | if (out != null) 99 | { 100 | out.close(); 101 | } 102 | } 103 | } 104 | 105 | private static void getAllFiles(File dir, List fileList) 106 | { 107 | File[] files = dir.listFiles(); 108 | for (File file : files) 109 | { 110 | fileList.add(file); 111 | if (file.isDirectory()) 112 | { 113 | getAllFiles(file, fileList); 114 | } 115 | } 116 | } 117 | 118 | private static void writeZipFile(File directoryToZip, List fileList, File zipFile) 119 | { 120 | 121 | try 122 | { 123 | FileOutputStream fos = new FileOutputStream(zipFile); 124 | ZipOutputStream zos = new ZipOutputStream(fos); 125 | 126 | for (File file : fileList) 127 | { 128 | if (file.exists() && !file.isDirectory()) 129 | { // we only zip files, not directories 130 | addToZip(directoryToZip, file, zos); 131 | } 132 | } 133 | 134 | zos.close(); 135 | fos.close(); 136 | } 137 | catch (FileNotFoundException e) 138 | { 139 | e.printStackTrace(); 140 | } 141 | catch (IOException e) 142 | { 143 | e.printStackTrace(); 144 | } 145 | } 146 | 147 | private static void addToZip(File directoryToZip, File file, ZipOutputStream zos) throws FileNotFoundException, IOException 148 | { 149 | 150 | FileInputStream fis = new FileInputStream(file); 151 | 152 | // we want the zipEntry's path to be a relative path that is relative 153 | // to the directory being zipped, so chop off the rest of the path 154 | String zipFilePath = file.getCanonicalPath().substring(directoryToZip.getCanonicalPath().length() + 1, 155 | file.getCanonicalPath().length()); 156 | System.out.println("Writing '" + zipFilePath + "' to zip file"); 157 | ZipEntry zipEntry = new ZipEntry(zipFilePath); 158 | zos.putNextEntry(zipEntry); 159 | 160 | byte[] bytes = new byte[1024]; 161 | int length; 162 | while ((length = fis.read(bytes)) >= 0) 163 | { 164 | zos.write(bytes, 0, length); 165 | } 166 | 167 | zos.closeEntry(); 168 | fis.close(); 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/res/anim/appsettings_overlay_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 17 | 18 | 38 | 39 | 46 | -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/res/anim/appsettings_overlay_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 17 | 18 | 36 | 37 | 44 | -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/res/drawable/appdrawergriditembackground.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/res/drawable/appselector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/res/drawable/appsettingsbackground.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 11 | -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/res/drawable/appsettingsselector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/res/drawable/infooverlaybackground.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 11 | -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/res/drawable/itemselector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/res/drawable/itemtextselector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/res/drawable/mainbackground.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 19 | -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/res/layout/appactivity.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/res/layout/appdrawergriditemlayout.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 18 | 19 | 27 | 28 | -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/res/layout/appdrawergriditemlayout_withbackground.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 18 | 19 | 32 | 33 | -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/res/layout/appsettingsoverlaydialog.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 14 | 15 | 16 | 17 | 24 | 25 | 30 | 31 | 40 | 41 | 50 | 51 | 61 | 62 | 70 | 71 | 76 | 77 | 78 | 79 | 87 | 88 | 99 | 100 | 108 | 109 | 114 | 115 | 116 | 117 | 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /SideQuestLauncher/AppStarter/src/main/res/layout/appupdateritemlayout.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 21 | 22 | 28 | 29 | 35 | 36 | 37 | 38 | 42 | 43 |