Android - application hasCode tag - android

Android developer page for <application> contains the flag hasCode. Its description says:
An application would not have any code of its own only if it's using
nothing but built-in component classes, such as an activity that uses
the AliasActivity class, a rare occurrence.
Can someone please give a code example of the AliasActivity use case (rare occurence) they talk about ?

An AliasActivity is - as the name suggests - just an alias to another activity.
You can create one just in XML. There is an example available in the Android git repository.
You manifest could look like this:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.aliasactivity">
<application android:hasCode="false" android:label="#string/app_label">
<activity android:name="android.app.AliasActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<meta-data android:name="android.app.alias"
android:resource="#xml/alias" />
</activity>
</application>
</manifest>
In res/xml/alias.xml you define the intent:
<alias xmlns:android="http://schemas.android.com/apk/res/android">
<intent android:action="android.intent.action.VIEW"
android:data="http://www.google.com/">
</intent>
</alias>

Related

ActivityNotFoundException: Shortcut could not be started

I'm trying to implement App Shortcuts to my app, but i can't get them work.
My shortcut.xml:
<Shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
<shortcut
android:shortcutId="shortcut"
android:enabled="true"
android:icon="#drawable/ic_shortcut"
android:shortcutShortLabel="#string/shortcut_label">
<intent
android:action="android.intent.action.VIEW"
android:targetPackage="com.example"
android:targetClass="com.example.package.Activity"/>
</shortcut>
manifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example">
<application
android:name=".Application"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:resizeableActivity="false"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".package.Activity"
android:label="#string/app_name"
android:launchMode="singleTask"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<meta-data
android:name="android.app.searchable"
android:resource="#xml/voice_search_params" />
<meta-data android:name="android.app.shortcuts"
android:resource="#xml/shortcuts" />
</activity>
So, i do shortcut same as in google example. I can see and click on shortcut, but nothing happens. I've tried different activities, changing activity location, activity action, params, like "exported=true", but nothing changes - in logs i can see only
ActivityNotFoundException: Shortcut could not be started
The only difference between my shortcut log, and google camera shortcut log is path to activity:
I/ActivityManager: START u0 {act=android.intent.action.VIEW flg=0x1000c000 cmp=com.example/.package.Activity}
vs
I/ActivityManager: START u0 {act=android.media.action.STILL_IMAGE_CAMERA flg=0x1000c000 cmp=com.google.android.GoogleCamera/com.android.camera.activity.CameraImageActivity}
Google cam has full path to activity, but package path differs.
PS: tried today google sample, static app shortcuts doesn't work in sample too. Dynamic app shortcuts work well.
In addition to Matin's answer, if you have multiple build types that change your application id, it won't work.
In my case, I had .debug and .qa suffix for application id. You can't reference to string reference or use variables inside intent element.
I found two solutions:
1) You will create different shortcuts.xml file for different build types and update your targetPackage.
For example,
<intent
android:action="com.example.ACTION"
android:targetClass="com.example.MainActivity"
android:targetPackage="com.example.debug"/>
2) There is a plugin that allows you to use applicationId variable in your XML file.
https://github.com/timfreiheit/ResourcePlaceholdersPlugin
android:targetPackage have to contain your application ID. So if you have defined your app id in build.gradle as applicationId "com.my.app.id" you have to use android:targetPackage="com.my.app.id"
Change the package name on your Activity to:
android:name=".Activity"
Change your shortcut target class to:
android:targetClass="com.example.Activity"
I also met this problem. Then i found that android:targetClass is not right path.
android:targetClass="com.example.camille.testappshortcuts.Main"
Main is app's access.
Maybe you should change Activity to another name, then add it.

How to use a different launcher activity in a product flavor?

I'm working on an Android library project, in the default src/main/AndroidManifest.xml, the MainActivity is the launcher activity.
For the sake of something else, I created product flavors. Yes, it works perfect if I want to trigger / show different activitis inside different product flavors. However, I wanna keep the default launcher activity from src/main/ folder, while register another flavored activity as the new launcher activity. So that for different product flavors, I could have different launcher activities, and from them I could still start original "launcher" activity in src/main/.
Could anyone kindly tell me how to achive that? Thanks a lot.
Notes:
Adding if (BuildConfig.FLAVOR.equals("flavorName")) code to original launcher activity is not prefered. Because I don't want to modify the production code from someone else (this is a library project).
I've tried manifestmerger and tools:replace, but seems like it doesn't work for intent-filter (I noticed that the element merging policy for intent-filter is always).
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
If this may work, could you please kindly guide me how to make it work? Thanks.
What I have tried:
Enabling Manifest Merger, which doesn't work;
Using activity-alias, which doesn't work either.
Finally I found out that the problem could be solved by just adding one line:
<category android:name="android.intent.category.DEFAULT" />
==================================================
To make it clear, I'll go through the problem and solution one more time:
Under src/main/java there is a MainActivity, and in corresponding src/main/AndroidManifest.xml it specifies MainActivity as the launcher activity:
<activity android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
That is a very easy part. Now we start with the product flavor part.
Due to some reason, in a product flavor, I don't want to overwrite the MainActivity, instead, I have a YetAnotherMainActivity. The goal is to set the YetAnotherMainActivity as the new launcher activity in the product flavor, and it should still be able to call MainActivity.
And here, is how you can set the new activity in product flavor as the new launcher activity:
flavorX/AndroidManifest.xml:
<activity android:name="com.example.YetAnotherMainActivity"
android:label="#string/title_yet_another_main_activity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
Yep, it turns out deadly easy. Just add android.intent.category.DEFAULT.
I think that <activity-alias> fits there more than any other solution (have no idea why #JingLi couldn't get it working. Maybe there were some troubles year ago, but for now it's okay).
For example, we have the following manifest in main:
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.application">
<application>
<activity android:name=".InfoActivity"/>
<activity-alias
android:name="com.example.application.Launcher"
android:targetActivity=".InfoActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
</application>
</manifest>
And we want to replace launcher activity with DebugInfoActivity from debug flavor. So, we need to just replace the targetActivity attribute in the specified <activity-alias> tag:
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application>
<activity android:name=".DebugInfoActivity"/>
<!-- to not litter the manifest -->
<activity
android:name="com.example.application.InfoActivity"
tools:node="remove"/>
<activity-alias
android:name="com.example.application.Launcher"
android:targetActivity=".DebugInfoActivity"
tools:replace="android:targetActivity"/>
</application>
</manifest>
Notes:
In the example we use the same package name for main and debug.
We have to enter the full name for activity-alias, so the merger can merge their correctly.
With the solution we also can inherit all attributes and childs from main activity-alias to not duplicate their in debug.
I guess I am not late :)
So today I got the same problem. #seroperson solution was correct but If you do not want the default launcher activity at all then just use the below code in your flavor's manifest:
<activity
android:name=".DefaultLauncherActivity"
tools:node="remove"
>
Android merger is merging intent-filter from main manifest lancher to flavors. I have not found way to prevent that. You end up with 2 app icons on device (each for launcher Activity).
Based on that, you cannot override completely settings from main manifest. Solition may be to keep only shell of manifest in main folder and implement manifest in each flavor or to remove conflict Activities from main folder and implemenent independently in each flavor.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.adamassistant.app">
<!-- empty shell, implementation in flavors folders -->
</manifest>
The simplest and cleanest solution is to keep only one Manifest and write two different MainActivity.java class one for each flavor in order to avoiding duplication of manifest nodes.
Given two flavors in gradle
productFlavors {
paid {
packageName "com.example"
}
demo {
packageName "com.example.demo"
}
}
Given this project structure
app/
|--libs/
|--src/
|--paid/
| |--java/
| |--com/example/
| |--MainActivity.java
|--demo/
| |--java/
| |--com/example/
| |--MainActivity.java
|--main/
|--java/
| |--...
|--res/
| |--...
|--AndroidManifest.xml
And this Android Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.flavors">
<application
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme">
<activity
android:name=".MainActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
Create a different AndroidManifest.xml file in your flavor. And there set your DifferentFlavorMainActivity.java as the launcher activity with full name like:
android:name="com.android.application.paid.MainActivity"
The working simplest solution is to use manifest merging and using
<intent-filter tools:node="removeAll">
as suggested in the following post :
Merging android manifest files, conflicting filter

Android manifest for USBAccesory

I am making an app that communicates with a piece of usb hardware made by my company (this is the only app allowed to talk to the usb accessory, it's not a public api). I am having difficulties setting up the proper launch modes in the manifest.
There are three components to the app: the main activity, a login activity, and the USBService.
I'm assuming the intent for the main goes to the login activity, and the intent for the usb goes to the USBService, but I am not sure if I do this, will this start the service if the app is not running? More over, if it does, how do I fetch an already existing service?
What type of structure should I be looking at for the manifest file? (specifically, intent-filters, and appropriate launch modes... I've read a few documents about the launch modes but I am still not sure I quite understand... There should only ever be at most one instance of each activity/service, and they need to communicate together.
edit: it is not necessary for communications to start before the app is open, nor is it necessary to launch the app automatically when the usb is connected.
edit: my manifest as it stands, looks like:
<uses-feature android:name="android.hardware.usb.accessory" />
<uses-sdk
android:minSdkVersion="15"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<activity
android:name="mainpackage.MainActivity"
android:label="#string/app_name"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
android:resource="#xml/accessory_filter" />
</activity>
<activity
android:name="mainpackage.LoginActivity"
android:label="#string/title_activity_login"
android:windowSoftInputMode="adjustResize|stateVisible" >
</activity>
<service android:name="updater.USBService"
android:exported="false" >
<!--
-->
</service>
</application>
in your manifest add
<manifest ...>
<uses-feature android:name="android.hardware.usb.host" />
<uses-sdk android:minSdkVersion="12" />
In this case, the following resource file should be saved in res/xml/device_filter.xml and specifies that any USB device with the specified attributes should be filtered:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<usb-device vendor-id="1234" product-id="5678" class="255" subclass="66" protocol="1" />
</resources>
Hope this help.
Your manifest looks good,
I think you make a good choice for putting the intent-filter "android.hardware.usb.action.USB_ACCESSORY_ATTACHED" in the mainActivity and start the application in this activity,
and again I think it's a good choice to start your mainActivity in SingleTop launch mode,
because if an instance of the mainActivity already exists at the top of the current task, the system going to launch this activity, no new instance of this activity will be created.
For a best understanding of the different launch mode available in android,
I think this link may help you :
http://www.intridea.com/blog/2011/6/16/android-understanding-activity-launchmode
To make a long story short I think you'll be all set with this manifest as is.
To Use Android Devices min SDK version should be set to 12 and need to declare following line in AndroidManifest.xml file
<>
<uses-sdk android:minSdkVersion="<version>" />
...
<application>
<uses-library android:name="com.android.future.usb.accessory" />
<activity ...>
...
<intent-filter>
<action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
</intent-filter>
<meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
android:resource="#xml/accessory_filter" />
</activity>
</application>

Setting Application Name in Android Devices

I implemented a android project named 'vignesh', in which i had source package as com.example.learn.android. In my tab while uninstalling the app, its showing com.example.learn instead of project name alone. Please advice..
You can specify your application label in the AndroidManifest.xml
<application
android:label="#string/app_name"
...>
</application>
In the above example you have to define app_name in res/strings.xml
<string name="app_name">My app name</string>
If this is not working in the AndroidManifest.xml file:
<application
android:label="#string/app_name"
...>
</application>
Look for the startup activity(the activity with the android.intent.action.MAIN & android.intent.category.LAUNCHER), example:
<activity
android:name=".SplashScreen"
android:label="com.example.learn"
android:noHistory="true"
android:screenOrientation="landscape"
android:theme="#android:style/Theme.NoTitleBar.Fullscreen" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
You probably have the android:label mentioned just like the example above. The strange thing is that Android takes your first activity's name (label) as app name (I don't know why).
If you just remove (or rename) the android:label="com.example.learn" line it should be ok. Removing the line ensures that the app will look for the android:label tag defined in the <application> part of the AndroidManifest.xml file.

Daydream settings

I'm trying to create a settings for my Daydream and according to the documentation, I need to create a xml file, like this:
<dream xmlns:android="http://schemas.android.com/apk/res/android"
android:settingsActivity="com.example.app/.MyDreamSettingsActivity" />
However, my Activity is in a library project (called com.project.base) and I keep getting this error in Logcat when clicking on the setting button:
11-16 23:01:29.331: E/AndroidRuntime(28908): android.content.ActivityNotFoundException: Unable to find explicit activity class {com.project.base/com.project.base.SettingsDayDream}; have you declared this activity in your AndroidManifest.xml?
I have my xml file setup like this:
<dream xmlns:android="http://schemas.android.com/apk/res/android"
android:settingsActivity="com.project.base/.SettingsDayDream" />
but I've tried all variation, such as com.project.base/com.project.base.SettingsDayDream
and just com.project.base.SettingsDayDream, but nothing seems to work.
I've declared the activity in the AndroidManifest.xml like this:
<activity android:name="com.project.base.SettingsDayDream" android:configChanges="keyboardHidden|orientation" />
as well as the service:
<service android:name="com.project.base.DayDream" android:exported="true" android:icon="#drawable/icon" android:label="#string/app_name">
<intent-filter>
<action android:name="android.service.dreams.DreamService" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data android:name="android.service.dream" android:resource="#xml/daydream" />
</service>
The problem is in your daydream.xml. The format for the android:settingsActivity is current.app.package/com.project.base.SettingsActivity
So current.app.package, before the /, needs to be your current app, not the library project.

Categories

Resources