diff --git a/android/cli/commands/_build.js b/android/cli/commands/_build.js index 522adb32ceb..b8efa274ea1 100644 --- a/android/cli/commands/_build.js +++ b/android/cli/commands/_build.js @@ -1047,6 +1047,9 @@ AndroidBuilder.prototype.validate = function validate(logger, config, cli) { try { if (cli.tiapp.android && cli.tiapp.android.manifest) { this.customAndroidManifest = AndroidManifest.fromXmlString(cli.tiapp.android.manifest); + + // check if we have nodes + this.activityAliasCount = this.customAndroidManifest.xmlDomDocument.getElementsByTagName('application')[0].getElementsByTagName('activity-alias').length; } } catch (ex) { logger.error(__n('Malformed definition in the section of the tiapp.xml')); @@ -3522,7 +3525,8 @@ AndroidBuilder.prototype.fetchNeededManifestSettings = function fetchNeededManif const neededSettings = { queries: neededQueriesDictionary, storagePermissionMaxSdkVersion: storagePermissionMaxSdkVersion, - usesPermissions: Object.keys(neededPermissionDictionary) + usesPermissions: Object.keys(neededPermissionDictionary), + skipLauncher: this.activityAliasCount > 0 }; return neededSettings; }; @@ -3619,7 +3623,8 @@ AndroidBuilder.prototype.generateAndroidManifest = async function generateAndroi storagePermissionMaxSdkVersion: neededManifestSettings.storagePermissionMaxSdkVersion, packageName: this.appid, queries: neededManifestSettings.queries, - usesPermissions: neededManifestSettings.usesPermissions + usesPermissions: neededManifestSettings.usesPermissions, + skipLauncher: this.activityAliasCount > 0 }); const mainManifest = AndroidManifest.fromXmlString(mainManifestContent); diff --git a/android/modules/app/src/java/ti/modules/titanium/app/AndroidModule.java b/android/modules/app/src/java/ti/modules/titanium/app/AndroidModule.java index 7ed4ad78a48..c70e4913283 100644 --- a/android/modules/app/src/java/ti/modules/titanium/app/AndroidModule.java +++ b/android/modules/app/src/java/ti/modules/titanium/app/AndroidModule.java @@ -6,6 +6,7 @@ */ package ti.modules.titanium.app; +import org.appcelerator.kroll.KrollDict; import org.appcelerator.kroll.KrollModule; import org.appcelerator.kroll.KrollRuntime; import org.appcelerator.kroll.annotations.Kroll; @@ -17,8 +18,10 @@ import org.appcelerator.titanium.proxy.RProxy; import android.app.Activity; +import android.content.ComponentName; import android.content.Intent; import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; @Kroll.module(parentModule = AppModule.class) @@ -61,6 +64,27 @@ public ActivityProxy getTopActivity() } } + @Kroll.method + public void changeIcon(KrollDict options) + { + if (options.containsKeyAndNotNull("from") && options.containsKeyAndNotNull("to")) { + String oldPackage = options.getString("from"); + String newPackage = options.getString("to"); + String pkgName = TiApplication.getInstance().getPackageName(); + + TiApplication.getInstance().getPackageManager().setComponentEnabledSetting( + new ComponentName(pkgName, pkgName + "." + oldPackage), + PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP + ); + TiApplication.getInstance().getPackageManager().setComponentEnabledSetting( + new ComponentName(pkgName, pkgName + "." + newPackage), + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP + ); + } else { + Log.e(TAG, "Parameters missing. Please provide 'from' and 'to'"); + } + } + @Kroll.getProperty public int getAppVersionCode() { diff --git a/android/templates/build/AndroidManifest.xml b/android/templates/build/AndroidManifest.xml index c74fc72ff2b..6da674828ac 100644 --- a/android/templates/build/AndroidManifest.xml +++ b/android/templates/build/AndroidManifest.xml @@ -38,7 +38,9 @@ android:alwaysRetainTaskState="true"> + <% if (!skipLauncher) { %> + <% } %> diff --git a/apidoc/Titanium/App/Android/Android.yml b/apidoc/Titanium/App/Android/Android.yml index 8f6e4adfa8e..f1996f8e3da 100644 --- a/apidoc/Titanium/App/Android/Android.yml +++ b/apidoc/Titanium/App/Android/Android.yml @@ -2,12 +2,27 @@ name: Titanium.App.Android summary: A module used to access Android application resources. description: | - For more information, refer to the official documentation on the Android Developer website about + For more information, refer to the official documentation on the Android Developer website about [application resources](https://developer.android.com/guide/topics/resources/index.html). extends: Titanium.Module since: "1.5" platforms: [android] +methods: + - name: changeIcon + summary: Changes the Android app icon at runtime. + description: | + You have to add `` nodes for every icon to the tiapp.xml and use `changeIcon()` to switch from one + to another. Check the the `Change Android icon at runtime` example for more details. The app has to keep track of + the current icon state in order to set the from/to parameters. + since: "12.7.0" + parameters: + - name: from + type: String + summary: `android:name` (without leading dot) of the current icon that is going to be deactivated. + - name: to + type: String + summary: `android:name` (without leading dot) of the icon that is going to be activated. properties: - name: R summary: The `R` namespace for application resources. @@ -33,14 +48,14 @@ properties: - name: appVersionCode summary: | - The version number of the application. + The version number of the application. type: Number permission: read-only since: 3.3.0 - + - name: appVersionName summary: | - The version name of the application. + The version name of the application. type: String permission: read-only since: 3.3.0 @@ -76,24 +91,71 @@ events: examples: - title: Custom String Resource example: | - - Custom Android resources may be placed in `platform/android` in the project root. - For example, to utilize a custom localization file, create and populate + + Custom Android resources may be placed in `platform/android` in the project root. + For example, to utilize a custom localization file, create and populate `platform/android/res/values/mystrings.xml` with the following data. - + ``` xml testing 1 2 3 ``` - + In Javascript, this can be accessed as follows. - + ``` js var activity = Ti.Android.currentActivity; var R = Ti.App.Android.R; - + var mystring = activity.getString(R.string.mystring); Ti.API.debug("mystring = " + mystring); ``` + - title: Change Android icon at runtime + example: | + + Add these `` nodes into the tiapp.xml `` block: + + ``` xml + + + + + + + + + + + + + ``` + + Change the `android:targetActivity` to point at your main activity, `android:name` is used inside the JavaScript code + to switch between the alias nodes and `android:icon` will be the new icon. + + In Javascript, this can be accessed as follows. + + ``` js + const win = Ti.UI.createWindow({layout: "vertical"}); + + const btn1 = Ti.UI.createButton({title: "switch to red"}); + const btn2 = Ti.UI.createButton({title: "switch to default"}); + + btn1.addEventListener("click", function() { + Ti.App.Android.changeIcon({ + from: "default", + to: "red" + }); + }); + btn2.addEventListener("click", function() { + Ti.App.Android.changeIcon({ + from: "red", + to: "default" + }); + }); + + win.add([btn1, btn2]); + win.open(); + ```