3

I am using following code in service to open the main/launcher Activity , the code worked fine until I declared this project as library and created two other projects which use this library.

So in the onStartCommand of service this code is written.

 final Notification notification = new Notification(R.drawable.ic_launcher, null, 0);   

    String notifTitle = "Service";
    String notifMessage = "Running";

    final Intent notificationIntent = new Intent(this,   MainActivity.class);
    notificationIntent.putExtra("extra", "value");
    notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
                            | Intent.FLAG_ACTIVITY_SINGLE_TOP);
    notificationIntent.setAction("android.intent.action.MAIN");
    notificationIntent.addCategory("android.intent.category.LAUNCHER");

    final PendingIntent contentIntent = PendingIntent
                            .getActivity(this, 0, notificationIntent,0);



    notification.setLatestEventInfo(this, notifTitle, notifMessage, contentIntent);     
    startForeground(17, notification);

MainActivity.class is part of library, two projects which use this library have their main Activities MainActivityA , MainActivityB which extend MainActivity of library.

Now the problem is when I click notification of service, MainActivityA or MainActivityB should be launched but right now nothing happens, but previously it worked when library was a project itself

Any ideas would be appreaciated alot ,

Thank you,

Ahmed
  • 14,503
  • 22
  • 92
  • 150

4 Answers4

1

You are hardcoding your intent

final Intent notificationIntent = new Intent(this,   MainActivity.class);

to launch your MainActivity.class not MainActivityA.class or MainActivityB.class. You'll have to pass into your service the correct class or change the intent to be more generic and let the Intent framework discover your activities (which may be unique to your apps).

I was in the process of writing something about intent filters but @smith324 beat me to it.

I would consider using meta-data rather than a string resource similar to:

<meta-data android:name="com.foo.service.LaunchName" android:value="com.foo.MainActivityA"></meta-data>

This avoids third-party string name collision should you add in additional libraries and in my opinion keeps the strings file cleaner for the developer as this is more for wiring of your classes rather than something that may need to be internationalization/translation for the users.

See: How do you add user defined properties/values in to the Android manifest file?

Community
  • 1
  • 1
Morrison Chang
  • 11,691
  • 3
  • 41
  • 77
  • yes I understand and that's why its not working, what I want to know is how to make the service choose correct activity for intent, or by some other means launch the Correct MainActivityA/B .. – Ahmed Nov 26 '12 at 04:30
  • So as you said make the Intent generic so that framework discovers Activity. How to make it generic ? code sample would be helpful. Thanks – Ahmed Nov 26 '12 at 04:32
1

There are a couple of ways to go about this.

You could declare an Intent Filter on an Activity in your manifest and broadcast the Intent, but this could be problematic if the user has both versions installed on their device. (There is a local broadcast in the support library that you could use instead docs)

Personally I would use Android's resource system to load the class name dynamically. Intents give you that ability to set the ComponentName which is the same thing as giving it a hardcoded reference the an Activity's class.

Intent i = new Intent();
String mPackage = ctx.getPackageName();
String mClass = ctx.getResources().getString(R.string.notification_class_name);
i.setComponent(new ComponentName(mPackage,mPackage+mClass));

The library project's values can be overridden by the projects that use them, so in both of these projects you have a value in strings.xml that corresponds to that app's notification activity.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="notification_class_name">.MainActivityA</string>
</resources>

You can then use this Intent with your pendingIntent and it will open the activity inside of the current application.

smith324
  • 13,020
  • 9
  • 37
  • 58
  • I used your approach to solve it, however using if else condition based on package name, thanks for help.. – Ahmed Nov 26 '12 at 18:40
  • How can we resolve " Unable to find explicit activity class...have you declared this activity in your AndroidManifest.xml?" The library's manfiest have no access to Activity in the project using this library. – BabyishTank May 25 '21 at 19:35
1

This is an old question but I came across this while trying to solve the problem myself. I figured out a simpler way to do this without having to configure any strings or passing in any parameters.

String packageName = getPackageName();
Intent notificationIntent = getPackageManager().getLaunchIntentForPackage(packageName);

Now you have the intent you can add on extras, etc.

darrenp
  • 154
  • 1
  • 6
0

To fetch the Launcher Activity, here is one way.

public static Class<?> GetLauncherActivity(Context context)
    {
        String packageName = context.getPackageName();
        Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName);
        String className = launchIntent.getComponent().getClassName();
        try
        {
            return Class.forName(className);
        }
        catch (ClassNotFoundException e)
        {
            e.printStackTrace();
            return null;
        }
    }
Ayyappa
  • 1,876
  • 1
  • 21
  • 41