I have created a library project that I am sharing across several apps. I implemented a simple session expiration feature that will kick the user back to the login screen after a certain time period.
The login screen activity is my main activity, so in the manifest it looks like this:
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/Theme.Sherlock.Light.DarkActionBar"
android:name="com.blah.application.MyApplication" >
<activity
android:name="com.blah.activity.LoginScreenActivity"
android:label="#string/title_activity_main"
android:screenOrientation="portrait"
android:configChanges="orientation|keyboardHidden"
android:windowSoftInputMode="adjustPan">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
When the session is expired, I want to kick the user back to the login screen, but I don't want to hardcode the name of the activity because it might be different depending on the specific app that is using the library. Here's what I was doing before:
Intent intent = new Intent(context, LoginScreenActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(intent);
This doesn't work if the app's main activity is something different than LoginScreenActivity. I don't want to hardcode "LoginScreenActivity.class", I want to programmatically determine the name of the main class and then direct the user to that activity...can someone help me out?
Thanks in advance!
EDIT
I found a way to accomplish the same end result, but it's definitely not great. Since there is a certain amount of configuration necessary for me to deploy a new app using the same library (strings, bools, etc), I added a string to the strings.xml file for the specific app that defines the "main" activity name for that app:
<string name="mainClassName">com.blah.specificapp.activity.SpecificAppLoginScreenActivity</string>
Then I can get a handle on that class by name and redirect the user there:
Class<?> clazz = null;
try
{
clazz = Class.forName(context.getString(R.string.mainClassName));
}
catch (ClassNotFoundException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
if(clazz != null)
{
Intent intent = new Intent(context, clazz);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(intent);
}
I know this is a god-awful solution, but it works. Like I said, there is a certain amount of configuration I have to do for each new app anyway, so adding one more string isn't a huge deal it's just not very elegant. I'd appreciate any suggestions that can accomplish the same goal without using my hack.
You can request a launch Intent from the PackageManager, using:
Intent launchIntent = PackageManager.getLaunchIntentForPackage(context.getPackageName());
This will return an Intent that you can use to launch the "main" activity (which I assume is your "login" activity). Just add Intent.FLAG_ACTIVITY_CLEAR_TOP to this and you should be good to go.
How about using a mime-type on your intent filter.
<activity android:name=".LoginActivity"
android:exported="true" android:launchMode="singleTop" android:label="#string/MT">
<intent-filter>
<category android:name="android.intent.category.DEFAULT"/>
<action android:name="com.foo.ACTION_LOGIN" />
<data android:mimeType="application/x.foo.com.mobile.login" />
</intent-filter>
</activity>
And launch the activity as follows:
Intent intent = new Intent();
intent.setAction("com.foo.ACTION_LOGIN");
intent.setType("application/x.foo.com.mobile.login");
startActivity(myIntent);
Thus the intent will be serviced by whatever activity is registered with this action/mime-type pair. I am not certain, but I think if that activity is hosted in the same app, it may be chosen first.
Related
To specify my "Home" activity at compile-time, I can use the following code in my AndroidManifest.
<activity
android:name=".HomeActivity"
<intent-filter android:label="#string/home_activity">
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
I have a requirement though where I need to be able to specify the activity I would like to use as my "Home" screen at "run-time". Does anyone know if this is possible? Basically, I want to replace "HomeActivity" with something else.
I looked into using an "activity-alias" where I can specify the target activity using the "targetActivity" attribute but I didn't quite get how I can use this.
Thanks!
#Jon you can conditionally call separate activity from splash.Like you have a condition that on first app launch you need to open a tutorial screen and then onwards your home Activity then you can create different intents.
if (!sharedPreferences.contains(DiceConstants.FIRST_TIME_PREFS)) {
intent = new Intent(this, TutorialActivity.class);
sharedPreferences.edit().putBoolean(DiceConstants.FIRST_TIME_PREFS, true).commit();
} else {
intent = new Intent(this, HomeActivity.class);
}
I’ve an android app and checked as library let it be Mainapp. Now I have created two separate app using that library viz. subapp1 and subapp2. Individual apps are running fine. I’ve login activity in the library package. On successful login user will be redirected to dashboard activity.
Written simply in loginactivity page of the library pack
Intent i = new Intent();
i.setClass(getApplicationContext(), UserhomeActivity.class);
startActivity(i);
Now I need to specify to which activity the user will be redirected based on the sub app. So how I can manage this without replicating the pages. Thanks.
you could provide the class and package name as an argument and start a new intent:
Intent sccuess = new Intent();
sccuess.setClassName(packageName, className);
startActivity(sccuess);
I am not sure I understand you correctly but If I understand you correct, you need to derive your activities from SecureActivity which user is supposed to be logged in to access there.
After you extend your classes from SecureActivity, you can check it in onResume() method.
Here is an example:
public class SecureActivity extends Activity
{
#Override
public void onResume()
{
// Check if user logged in or not.
}
}
public class YourActivity extends SecureActivity
{
// ...
}
In the Mainifest of your Library, your should define like that
<activity
android:name="com.gmail.app.activities.A_Activity"
android:label="#string/app_name"
android:screenOrientation="portrait"
android:theme="#style/NoActionBar" >
<intent-filter>
<action android:name="com.gmail.app.A.Fire_Activity" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name="com.gmail.app.activities.B_Activity"
android:label="#string/app_name"
android:screenOrientation="portrait"
android:theme="#style/NoActionBar" >
<intent-filter>
<action android:name="com.gmail.app.B.Fire_Activity" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
In library code where to fire the intent:
Intent i = new Intent(_context.getPackageName() + ".Fire_Activity");
//Action will be like com.gmail.app.A.Fire_Activity or com.gmail.app.B.Fire_Activity
startActivity(i);
PS:
Your Sub-Apps have package-names:
com.gmail.app.A
com.gmail.app.B
Well I searched a lot, but I didn't find a precise answer how to export an Activity, so an app can start it with startActivityforResult.
How do I achieve that? Do I have to change the Manifest in some ways?
As an alternate to Dalmas' answer, you can actually export an Activity without creating an <intent-filter> (along with the hassle of coming up with a custom action).
In the Manifest edit your Activity tag like so:
<activity
android:name=".SomeActivity"
....
android:exported="true" />
The important part is android:exported="true", this export tag determines "whether or not the activity can be launched by components of other applications". If your <activity> contains an <intent-filter> then this tag is set to true automatically, if it does not then it is set to false by default.
Then to launch the Activity do this:
Intent i = new Intent();
i.setComponent(new ComponentName("package name", "fully-qualified name of activity"));
startActivity(i);
Of course with this method you will need to know the exact name of the Activity you are trying to launch.
You need to declare an intent-filter in your Manifest (I took the following example from Barcode Scanner) :
<activity android:name="...">
<intent-filter>
<action android:name="com.google.zxing.client.android.SCAN" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
Then create an intent with the same action string :
Intent intent = new Intent("com.google.zxing.client.android.SCAN");
startActivityForResult(intent, code);
Android should start your activity (or it will show a drop-down box if there are multiple apps sharing the same action string).
i'm trying to do something that is described briefly on the next link:
link
meaning, i have an activity that can be even on another application (but for now let's focus on an activity that my app has) , which i want to be able to create a shortcut to it.
for terminology , let's say that the activity that creates the shortcut is named "ShortcutCreatorActivity" ,and the activity that gets started is "MyActivity" .
what i got from what is written is that the ShortcutCreatorActivity should be defined in the manifest as:
<activity android:icon="#drawable/ic_launcher"
android:label="ShortcutActivity" android:name="com.my_app.ShortcutCreatorActivity">
<intent-filter>
<action android:name="android.intent.action.CREATE_SHORTCUT" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
and what i got in its java code is:
public class ShortcutCreatorActivity extends Activity
{
#Override
protected void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
final Intent shortcutIntent=new Intent("com.my_app.MyActivity");
final ShortcutIconResource iconResource=Intent.ShortcutIconResource.fromContext(this,R.drawable.ic_launcher);
final Intent intent=new Intent();
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT,shortcutIntent);
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME,"Shortcut Test");
intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,iconResource);
setResult(RESULT_OK,intent);
Toast.makeText(this,"shortcut created",Toast.LENGTH_SHORT).show();
finish();
}
}
yet i keep getting the same message of "application not found" when clicking on the shortcut , and the log :
ActivityManager(232): Starting: Intent { act=com.my_app.MyActivity flg=0x10200000 bnds=[80,150][160,250] } from pid 3956
can anyone please help me? what is missing?
i've also tried some intent filters for the MyActivity activity inside the manifest. nothing helped...
#liro
i don't think it matters , since i've specified the exact full path to the class , including the package name.
everyone, please, if you have a working project, that would be perfect .
Not sure here, but I think you need to remove the "com" from "com.MyActivity."
<activity android:icon="#drawable/ic_launcher"
android:label="ShortcutActivity" android:name=".ShortcutCreatorActivity">
<intent-filter>
<action android:name="android.intent.action.CREATE_SHORTCUT" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
Instead of
final Intent shortcutIntent=new Intent("com.my_app.MyActivity");
try
final Intent shortcutIntent=new Intent(this, com.my_app.MyActivity.class);
or define your action in intent-filter of that activity, which I believe you may did not.
Those two links may be helpful:
http://developer.android.com/reference/android/content/Intent.html#Intent(java.lang.String)
http://developer.android.com/guide/topics/manifest/action-element.html
I am getting an ActivityNotFoundException in the following code:
Main.java
Intent intent = new Intent();
intent.setAction("com.test.app.TEST");
startActivity(intent); // ActivityNotFoundException
Manifest.xml
<activity android:name=".MainActivity" android:theme="#android:style/Theme.Dialog">
<intent-filter>
<action android:name="com.test.app.TEST" />
</intent-filter>
</activity>
I've had this issue too, as perfectly concisely described by jpahn.
the period at the front did not give any help to me.
even with exactly this (a copy of the original question including edits), I would still get ActivityNotFoundException.
Main.java
Intent intent = new Intent();
intent.setAction("com.test.app.TEST");
startActivity(intent); // ActivityNotFoundException
Manifest.xml
<activity android:name=".MainActivity" android:theme="#android:style/Theme.Dialog">
<intent-filter>
<action android:name="com.test.app.TEST" />
</intent-filter>
</activity>
This was resolved, after much trial-and-error, by simply adding this to the intent-filter in the manifest:
<category android:name="android.intent.category.DEFAULT" />
So the final manifest file contained:
<activity android:name=".MainActivity" android:theme="#android:style/Theme.Dialog">
<intent-filter>
<action android:name="com.test.app.TEST" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
I got this error after moving an activity class from one package to another.
Clean build solved it (Project -> Clean).
Be sure to declare your activity in the manifest.xml within the aplication:
<application>
<activity android:name=".YourNewActivity"/>
</application>
To start the new Activity:
Intent intent = new Intent(main.this, YourNewActivity.class);
startActivity(intent);
Where main stands for the current activity,
Add a . (dot) before your activity name in Android Manifest. So it should be android:name=".WordsToSpeakMainActivity"
I have some addition to the #Tom Pace answer. The answer is completely right, but to make it more clear:
ActivityNotFoundException occurs because of absence of
<category android:name="android.intent.category.DEFAULT" />
Because when Android OS see this in the manifest file, understands that this activity can receive intent.
The point ActivityNotFoundException thrown is that, when activity(intent-creator-activity) tries to create intent for other activity(intent-receiver-activity), Android OS sees there is intent for receiver activity but receiver activity does not receive anyone. Then Android OS returns null or empty intent to intent-creator-activity. And startActivity throws that exception.
I have found a code from android developers to avoid this exception:
// Verify the original intent will resolve to at least one activity
if (sendIntent.resolveActivity(getPackageManager()) != null) {
startActivity(chooser);
}
Android Developers: Intent Filters
To be safe you can also call your new activity like this:
Intent intent = new Intent();
intent.setClass(this, THECLASSNAME);
startActivity(intent); //
However, you must add the activity to the androidmanifest - and write a . in front of it, e.g.
<activity android:name=".YOURACTIVITYNAME"></activity>
There two types of intents in android framework,
1-Implicit intents that you are using,
<activity android:name=".MainActivity" android:theme="#android:style/Theme.Dialog">
<intent-filter>
<action android:name="com.test.app.TEST" />
</intent-filter>
</activity>
just add one line in intent filter
<intent-filter>
<action android:name="com.test.app.TEST" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
2- Explicit Intents
Intent i=new Intent(CurrentActivity.this,WhereWeWantToGoActivity.class);
startActivity(i);
To launch an activity by a string definition, use:
Intent intent = new Intent();
intent.setComponent(
new ComponentName("com.app", "com.app.activity.TheActivity"));
startActivity(intent);
At the very top of your AndroidManifest.xml, you'll see the package attribute
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.example"
and then, in the activity tag, you'll see the name attribute:
<activity
android:name=".Something"
Make sure that the package name and activity name, when joined together, make the full package specification of your Activity i.e.
com.android.example + .Something = com.android.example.Something
Otherwise, you'll get a ActivityNotFoundException.
I found a solution to this problem... I´m using 2 modules in a android studio project, the thing here is that I needed to add the activity to the main manifest file
<activity android:name="com.HeadApp.ARTry.UnityPlayerActivity"
android:clearTaskOnLaunch="false" android:label="#string/app_name"
android:screenOrientation="portrait"
android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen"
/>
I had that in the unity activity manifest, I just copied the activity and paste it in the main manifest and that was it, hope it helps, eve been struggling a lot with this for the past 3 weeks