Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 85d558cd authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Add Activity API to get referrer information.

This expands the use of EXTRA_REFERRER to be relevant anywhere,
allowing apps to supply referrer information if they want.  However,
if they don't explicitly supply it, then the platform now keeps
track of package names that go with Intents when delivering them
to apps, which it can be returned as the default value.

The new method Activity.getReferrer() is used to retrieve this
referrer information.  It knows about EXTRA_REFERRER, it can return
the default package name tracked internally, and it also can return
a new EXTRA_REFERRER_NAME if that exists.  The latter is needed
because we can't use EXTRA_REFERRER in some cases since it is a Uri,
and things like #Intent; URI extras can only generate primitive type
extras.  We really need to support this syntax for referrers, so we
need to have this additional extra field as an option.

When a referrer is to a native app, we are adopting the android-app
scheme.  Since we are doing this, Intent's URI creation and parsing
now supports this scheme, and we improve its syntax to be able to build
intents with custom actions and stuff, instead of being all hung up
on custom schemes.

While doing this, fixed a problem when parsing both intent: and new
android-app: schemes with a selector portion, where we were not
respecting any scheme that was specified.

Change-Id: I06e55221e21a8156c1d6ac755a254fea386917a2
parent 993e3d2d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -559,6 +559,7 @@ aidl_files := \
	frameworks/base/core/java/android/content/pm/ProviderInfo.aidl \
	frameworks/base/core/java/android/content/pm/PackageStats.aidl \
	frameworks/base/core/java/android/content/pm/PermissionGroupInfo.aidl \
	frameworks/base/core/java/android/content/pm/LabeledIntent.aidl \
	frameworks/base/core/java/android/content/ComponentName.aidl \
	frameworks/base/core/java/android/content/SyncStats.aidl \
	frameworks/base/core/java/android/content/ContentValues.aidl \
+3 −0
Original line number Diff line number Diff line
@@ -3303,6 +3303,7 @@ package android.app {
    method public final android.app.Activity getParent();
    method public android.content.Intent getParentActivityIntent();
    method public android.content.SharedPreferences getPreferences(int);
    method public android.net.Uri getReferrer();
    method public int getRequestedOrientation();
    method public int getTaskId();
    method public final java.lang.CharSequence getTitle();
@@ -7750,6 +7751,7 @@ package android.content {
    field public static final java.lang.String EXTRA_ORIGINATING_URI = "android.intent.extra.ORIGINATING_URI";
    field public static final java.lang.String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER";
    field public static final java.lang.String EXTRA_REFERRER = "android.intent.extra.REFERRER";
    field public static final java.lang.String EXTRA_REFERRER_NAME = "android.intent.extra.REFERRER_NAME";
    field public static final java.lang.String EXTRA_REMOTE_INTENT_TOKEN = "android.intent.extra.remote_intent_token";
    field public static final java.lang.String EXTRA_REPLACEMENT_EXTRAS = "android.intent.extra.REPLACEMENT_EXTRAS";
    field public static final java.lang.String EXTRA_REPLACING = "android.intent.extra.REPLACING";
@@ -7809,6 +7811,7 @@ package android.content {
    field public static final int FLAG_RECEIVER_REGISTERED_ONLY = 1073741824; // 0x40000000
    field public static final int FLAG_RECEIVER_REPLACE_PENDING = 536870912; // 0x20000000
    field public static final java.lang.String METADATA_DOCK_HOME = "android.dock_home";
    field public static final int URI_ANDROID_APP_SCHEME = 2; // 0x2
    field public static final int URI_INTENT_SCHEME = 1; // 0x1
  }
+18 −6
Original line number Diff line number Diff line
@@ -127,6 +127,7 @@ public class Am extends BaseCommand {
                "       am screen-compat [on|off] <PACKAGE>\n" +
                "       am to-uri [INTENT]\n" +
                "       am to-intent-uri [INTENT]\n" +
                "       am to-app-uri [INTENT]\n" +
                "       am switch-user <USER_ID>\n" +
                "       am start-user <USER_ID>\n" +
                "       am stop-user <USER_ID>\n" +
@@ -229,6 +230,8 @@ public class Am extends BaseCommand {
                "\n" +
                "am to-intent-uri: print the given Intent specification as an intent: URI.\n" +
                "\n" +
                "am to-app-uri: print the given Intent specification as an android-app: URI.\n" +
                "\n" +
                "am switch-user: switch to put USER_ID in the foreground, starting\n" +
                "  execution of that user if it is currently stopped.\n" +
                "\n" +
@@ -270,7 +273,7 @@ public class Am extends BaseCommand {
                "    [--efa <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]\n" +
                "    [--esa <EXTRA_KEY> <EXTRA_STRING_VALUE>[,<EXTRA_STRING_VALUE...]]\n" +
                "        (to embed a comma into a string escape it using \"\\,\")\n" +
                "    [-n <COMPONENT>] [-f <FLAGS>]\n" +
                "    [-n <COMPONENT>] [-p <PACKAGE>] [-f <FLAGS>]\n" +
                "    [--grant-read-uri-permission] [--grant-write-uri-permission]\n" +
                "    [--grant-persistable-uri-permission] [--grant-prefix-uri-permission]\n" +
                "    [--debug-log-resolution] [--exclude-stopped-packages]\n" +
@@ -337,9 +340,11 @@ public class Am extends BaseCommand {
        } else if (op.equals("screen-compat")) {
            runScreenCompat();
        } else if (op.equals("to-uri")) {
            runToUri(false);
            runToUri(0);
        } else if (op.equals("to-intent-uri")) {
            runToUri(true);
            runToUri(Intent.URI_INTENT_SCHEME);
        } else if (op.equals("to-app-uri")) {
            runToUri(Intent.URI_ANDROID_APP_SCHEME);
        } else if (op.equals("switch-user")) {
            runSwitchUser();
        } else if (op.equals("start-user")) {
@@ -502,6 +507,12 @@ public class Am extends BaseCommand {
                if (intent == baseIntent) {
                    hasIntentInfo = true;
                }
            } else if (opt.equals("-p")) {
                String str = nextArgRequired();
                intent.setPackage(str);
                if (intent == baseIntent) {
                    hasIntentInfo = true;
                }
            } else if (opt.equals("-f")) {
                String str = nextArgRequired();
                intent.setFlags(Integer.decode(str).intValue());
@@ -607,7 +618,8 @@ public class Am extends BaseCommand {
        } else if (arg.indexOf(':') >= 0) {
            // The argument is a URI.  Fully parse it, and use that result
            // to fill in any data not specified so far.
            baseIntent = Intent.parseUri(arg, Intent.URI_INTENT_SCHEME);
            baseIntent = Intent.parseUri(arg, Intent.URI_INTENT_SCHEME
                    | Intent.URI_ANDROID_APP_SCHEME);
        } else if (arg.indexOf('/') >= 0) {
            // The argument is a component name.  Build an Intent to launch
            // it.
@@ -1549,9 +1561,9 @@ public class Am extends BaseCommand {
        } while (packageName != null);
    }

    private void runToUri(boolean intentScheme) throws Exception {
    private void runToUri(int flags) throws Exception {
        Intent intent = makeIntent(UserHandle.USER_CURRENT);
        System.out.println(intent.toUri(intentScheme ? Intent.URI_INTENT_SCHEME : 0));
        System.out.println(intent.toUri(flags));
    }

    private class IntentReceiver extends IIntentReceiver.Stub {
+36 −1
Original line number Diff line number Diff line
@@ -693,6 +693,7 @@ public class Activity extends ContextThemeWrapper
    /*package*/ String mEmbeddedID;
    private Application mApplication;
    /*package*/ Intent mIntent;
    /*package*/ String mReferrer;
    private ComponentName mComponent;
    /*package*/ ActivityInfo mActivityInfo;
    /*package*/ ActivityThread mMainThread;
@@ -4447,6 +4448,39 @@ public class Activity extends ContextThemeWrapper
        }
    }

    /**
     * Return information about who launched this activity.  If the launching Intent
     * contains an {@link android.content.Intent#EXTRA_REFERRER Intent.EXTRA_REFERRER},
     * that will be returned as-is; otherwise, if known, an
     * {@link Intent#URI_ANDROID_APP_SCHEME android-app:} referrer URI containing the
     * package name that started the Intent will be returned.  This may return null if no
     * referrer can be identified -- it is neither explicitly specified, nor is it known which
     * application package was involved.
     *
     * <p>If called while inside the handling of {@link #onNewIntent}, this function will
     * return the referrer that submitted that new intent to the activity.  Otherwise, it
     * always returns the referrer of the original Intent.</p>
     *
     * <p>Note that this is <em>not</em> a security feature -- you can not trust the
     * referrer information, applications can spoof it.</p>
     */
    @Nullable
    public Uri getReferrer() {
        Intent intent = getIntent();
        Uri referrer = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
        if (referrer != null) {
            return referrer;
        }
        String referrerName = intent.getStringExtra(Intent.EXTRA_REFERRER_NAME);
        if (referrerName != null) {
            return Uri.parse(referrerName);
        }
        if (mReferrer != null) {
            return new Uri.Builder().scheme("android-app").authority(mReferrer).build();
        }
        return null;
    }

    /**
     * Return the name of the package that invoked this activity.  This is who
     * the data in {@link #setResult setResult()} will be sent to.  You can
@@ -5868,7 +5902,7 @@ public class Activity extends ContextThemeWrapper
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, IVoiceInteractor voiceInteractor) {
            Configuration config, String referrer, IVoiceInteractor voiceInteractor) {
        attachBaseContext(context);

        mFragments.attachActivity(this, mContainer, null);
@@ -5891,6 +5925,7 @@ public class Activity extends ContextThemeWrapper
        mIdent = ident;
        mApplication = application;
        mIntent = intent;
        mReferrer = referrer;
        mComponent = intent.getComponent();
        mActivityInfo = info;
        mTitle = title;
+13 −12
Original line number Diff line number Diff line
@@ -94,6 +94,7 @@ import android.renderscript.RenderScript;
import android.security.AndroidKeyStoreProvider;

import com.android.internal.app.IVoiceInteractor;
import com.android.internal.content.ReferrerIntent;
import com.android.internal.os.BinderInternal;
import com.android.internal.os.RuntimeInit;
import com.android.internal.os.SamplingProfilerIntegration;
@@ -268,6 +269,7 @@ public final class ActivityThread {
        IBinder token;
        int ident;
        Intent intent;
        String referrer;
        IVoiceInteractor voiceInteractor;
        Bundle state;
        PersistableBundle persistentState;
@@ -290,7 +292,7 @@ public final class ActivityThread {
        LoadedApk packageInfo;

        List<ResultInfo> pendingResults;
        List<Intent> pendingIntents;
        List<ReferrerIntent> pendingIntents;

        boolean startsNotResumed;
        boolean isForward;
@@ -348,7 +350,7 @@ public final class ActivityThread {
    }

    static final class NewIntentData {
        List<Intent> intents;
        List<ReferrerIntent> intents;
        IBinder token;
        public String toString() {
            return "NewIntentData{intents=" + intents + " token=" + token + "}";
@@ -605,9 +607,9 @@ public final class ActivityThread {
        // activity itself back to the activity manager. (matters more with ipc)
        public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
                IVoiceInteractor voiceInteractor, int procState, Bundle state,
                String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state,
                PersistableBundle persistentState, List<ResultInfo> pendingResults,
                List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
                List<ReferrerIntent> pendingNewIntents, boolean notResumed, boolean isForward,
                ProfilerInfo profilerInfo) {

            updateProcessState(procState, false);
@@ -617,6 +619,7 @@ public final class ActivityThread {
            r.token = token;
            r.ident = ident;
            r.intent = intent;
            r.referrer = referrer;
            r.voiceInteractor = voiceInteractor;
            r.activityInfo = info;
            r.compatInfo = compatInfo;
@@ -637,13 +640,13 @@ public final class ActivityThread {
        }

        public final void scheduleRelaunchActivity(IBinder token,
                List<ResultInfo> pendingResults, List<Intent> pendingNewIntents,
                List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
                int configChanges, boolean notResumed, Configuration config) {
            requestRelaunchActivity(token, pendingResults, pendingNewIntents,
                    configChanges, notResumed, config, true);
        }

        public final void scheduleNewIntent(List<Intent> intents, IBinder token) {
        public final void scheduleNewIntent(List<ReferrerIntent> intents, IBinder token) {
            NewIntentData data = new NewIntentData();
            data.intents = intents;
            data.token = token;
@@ -2234,7 +2237,7 @@ public final class ActivityThread {
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.voiceInteractor);
                        r.referrer, r.voiceInteractor);

                if (customIntent != null) {
                    activity.mIntent = customIntent;
@@ -2421,8 +2424,7 @@ public final class ActivityThread {
        }
    }

    private void deliverNewIntents(ActivityClientRecord r,
            List<Intent> intents) {
    private void deliverNewIntents(ActivityClientRecord r, List<ReferrerIntent> intents) {
        final int N = intents.size();
        for (int i=0; i<N; i++) {
            Intent intent = intents.get(i);
@@ -2433,8 +2435,7 @@ public final class ActivityThread {
        }
    }

    public final void performNewIntents(IBinder token,
            List<Intent> intents) {
    public final void performNewIntents(IBinder token, List<ReferrerIntent> intents) {
        ActivityClientRecord r = mActivities.get(token);
        if (r != null) {
            final boolean resumed = !r.paused;
@@ -3752,7 +3753,7 @@ public final class ActivityThread {
    }

    public final void requestRelaunchActivity(IBinder token,
            List<ResultInfo> pendingResults, List<Intent> pendingNewIntents,
            List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
            int configChanges, boolean notResumed, Configuration config,
            boolean fromServer) {
        ActivityClientRecord target = null;
Loading