FileDocCategorySizeDatePackage
ResolverActivity.javaAPI DocAndroid 5.1 API49624Thu Mar 12 22:22:10 GMT 2015com.android.internal.app

ResolverActivity

public class ResolverActivity extends android.app.Activity implements AdapterView.OnItemClickListener
This activity is displayed when the system attempts to start an Intent for which there is more than one matching activity, allowing the user to decide which to go to. It is not normally used directly by application developers.

Fields Summary
private static final String
TAG
private static final boolean
DEBUG
private int
mLaunchedFromUid
private ResolveListAdapter
mAdapter
private android.content.pm.PackageManager
mPm
private boolean
mSafeForwardingMode
private boolean
mAlwaysUseOption
private boolean
mShowExtended
private android.widget.ListView
mListView
private android.widget.Button
mAlwaysButton
private android.widget.Button
mOnceButton
private android.view.View
mProfileView
private int
mIconDpi
private int
mIconSize
private int
mMaxColumns
private int
mLastSelected
private boolean
mResolvingHome
private int
mProfileSwitchMessageId
private android.content.Intent
mIntent
private android.app.usage.UsageStatsManager
mUsm
private Map
mStats
private static final long
USAGE_STATS_PERIOD
private boolean
mRegistered
private final com.android.internal.content.PackageMonitor
mPackageMonitor
Constructors Summary
Methods Summary
voidbindProfileView()

        final DisplayResolveInfo dri = mAdapter.getOtherProfile();
        if (dri != null) {
            mProfileView.setVisibility(View.VISIBLE);
            final ImageView icon = (ImageView) mProfileView.findViewById(R.id.icon);
            final TextView text = (TextView) mProfileView.findViewById(R.id.text1);
            if (dri.displayIcon == null) {
                new LoadIconTask().execute(dri);
            }
            icon.setImageDrawable(dri.displayIcon);
            text.setText(dri.displayLabel);
        } else {
            mProfileView.setVisibility(View.GONE);
        }
    
voiddismiss()

        if (!isFinishing()) {
            finish();
        }
    
android.graphics.drawable.DrawablegetIcon(android.content.res.Resources res, int resId)

        Drawable result;
        try {
            result = res.getDrawableForDensity(resId, mIconDpi);
        } catch (Resources.NotFoundException e) {
            result = null;
        }

        return result;
    
public android.content.IntentgetReplacementIntent(android.content.pm.ActivityInfo aInfo, android.content.Intent defIntent)
Replace me in subclasses!

        return defIntent;
    
protected java.lang.CharSequencegetTitleForAction(java.lang.String action, int defaultTitleRes)

        final ActionTitle title = mResolvingHome ? ActionTitle.HOME : ActionTitle.forAction(action);
        final boolean named = mAdapter.hasFilteredItem();
        if (title == ActionTitle.DEFAULT && defaultTitleRes != 0) {
            return getString(defaultTitleRes);
        } else {
            return named ? getString(title.namedTitleRes, mAdapter.getFilteredItem().displayLabel) :
                    getString(title.titleRes);
        }
    
private booleanhasManagedProfile()

        UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
        if (userManager == null) {
            return false;
        }

        try {
            List<UserInfo> profiles = userManager.getProfiles(getUserId());
            for (UserInfo userInfo : profiles) {
                if (userInfo != null && userInfo.isManagedProfile()) {
                    return true;
                }
            }
        } catch (SecurityException e) {
            return false;
        }
        return false;
    
android.content.IntentintentForDisplayResolveInfo(com.android.internal.app.ResolverActivity$DisplayResolveInfo dri)

        Intent intent = new Intent(dri.origIntent != null ? dri.origIntent :
                getReplacementIntent(dri.ri.activityInfo, mIntent));
        intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
                |Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
        ActivityInfo ai = dri.ri.activityInfo;
        intent.setComponent(new ComponentName(
                ai.applicationInfo.packageName, ai.name));
        return intent;
    
static final booleanisSpecificUriMatch(int match)

        match = match&IntentFilter.MATCH_CATEGORY_MASK;
        return match >= IntentFilter.MATCH_CATEGORY_HOST
                && match <= IntentFilter.MATCH_CATEGORY_PATH;
    
android.graphics.drawable.DrawableloadIconForResolveInfo(android.content.pm.ResolveInfo ri)

        Drawable dr;
        try {
            if (ri.resolvePackageName != null && ri.icon != 0) {
                dr = getIcon(mPm.getResourcesForApplication(ri.resolvePackageName), ri.icon);
                if (dr != null) {
                    return dr;
                }
            }
            final int iconRes = ri.getIconResource();
            if (iconRes != 0) {
                dr = getIcon(mPm.getResourcesForApplication(ri.activityInfo.packageName), iconRes);
                if (dr != null) {
                    return dr;
                }
            }
        } catch (NameNotFoundException e) {
            Log.e(TAG, "Couldn't find resources for package", e);
        }
        return ri.loadIcon(mPm);
    
private android.content.IntentmakeMyIntent()

        Intent intent = new Intent(getIntent());
        intent.setComponent(null);
        // The resolver activity is set to be hidden from recent tasks.
        // we don't want this attribute to be propagated to the next activity
        // being launched.  Note that if the original Intent also had this
        // flag set, we are now losing it.  That should be a very rare case
        // and we can live with this.
        intent.setFlags(intent.getFlags()&~Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
        return intent;
    
public voidonActivityStarted(android.content.Intent intent)

        // Do nothing
    
public voidonButtonClick(android.view.View v)

        final int id = v.getId();
        startSelected(mAlwaysUseOption ?
                mListView.getCheckedItemPosition() : mAdapter.getFilteredPosition(),
                id == R.id.button_always,
                mAlwaysUseOption);
        dismiss();
    
protected voidonCreate(android.os.Bundle savedInstanceState)

        // Use a specialized prompt when we're handling the 'Home' app startActivity()
        final Intent intent = makeMyIntent();
        final Set<String> categories = intent.getCategories();
        if (Intent.ACTION_MAIN.equals(intent.getAction())
                && categories != null
                && categories.size() == 1
                && categories.contains(Intent.CATEGORY_HOME)) {
            // Note: this field is not set to true in the compatibility version.
            mResolvingHome = true;
        }

        setSafeForwardingMode(true);

        onCreate(savedInstanceState, intent, null, 0, null, null, true);
    
protected voidonCreate(android.os.Bundle savedInstanceState, android.content.Intent intent, java.lang.CharSequence title, android.content.Intent[] initialIntents, java.util.List rList, boolean alwaysUseOption)
Compatibility version for other bundled services that use this ocerload without a default title resource

        onCreate(savedInstanceState, intent, title, 0, initialIntents, rList, alwaysUseOption);
    
protected voidonCreate(android.os.Bundle savedInstanceState, android.content.Intent intent, java.lang.CharSequence title, int defaultTitleRes, android.content.Intent[] initialIntents, java.util.List rList, boolean alwaysUseOption)

        setTheme(R.style.Theme_DeviceDefault_Resolver);
        super.onCreate(savedInstanceState);

        // Determine whether we should show that intent is forwarded
        // from managed profile to owner or other way around.
        setProfileSwitchMessageId(intent.getContentUserHint());

        try {
            mLaunchedFromUid = ActivityManagerNative.getDefault().getLaunchedFromUid(
                    getActivityToken());
        } catch (RemoteException e) {
            mLaunchedFromUid = -1;
        }
        mPm = getPackageManager();
        mUsm = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE);

        final long sinceTime = System.currentTimeMillis() - USAGE_STATS_PERIOD;
        mStats = mUsm.queryAndAggregateUsageStats(sinceTime, System.currentTimeMillis());

        mMaxColumns = getResources().getInteger(R.integer.config_maxResolverActivityColumns);

        mPackageMonitor.register(this, getMainLooper(), false);
        mRegistered = true;

        final ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
        mIconDpi = am.getLauncherLargeIconDensity();
        mIconSize = am.getLauncherLargeIconSize();

        mIntent = new Intent(intent);
        mAdapter = new ResolveListAdapter(this, initialIntents, rList,
                mLaunchedFromUid, alwaysUseOption);

        final int layoutId;
        final boolean useHeader;
        if (mAdapter.hasFilteredItem()) {
            layoutId = R.layout.resolver_list_with_default;
            alwaysUseOption = false;
            useHeader = true;
        } else {
            useHeader = false;
            layoutId = R.layout.resolver_list;
        }
        mAlwaysUseOption = alwaysUseOption;

        if (mLaunchedFromUid < 0 || UserHandle.isIsolated(mLaunchedFromUid)) {
            // Gulp!
            finish();
            return;
        }

        int count = mAdapter.mList.size();
        if (count > 1 || (count == 1 && mAdapter.getOtherProfile() != null)) {
            setContentView(layoutId);
            mListView = (ListView) findViewById(R.id.resolver_list);
            mListView.setAdapter(mAdapter);
            mListView.setOnItemClickListener(this);
            mListView.setOnItemLongClickListener(new ItemLongClickListener());

            if (alwaysUseOption) {
                mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
            }

            if (useHeader) {
                mListView.addHeaderView(LayoutInflater.from(this).inflate(
                        R.layout.resolver_different_item_header, mListView, false));
            }
        } else if (count == 1) {
            safelyStartActivity(mAdapter.intentForPosition(0, false));
            mPackageMonitor.unregister();
            mRegistered = false;
            finish();
            return;
        } else {
            setContentView(R.layout.resolver_list);

            final TextView empty = (TextView) findViewById(R.id.empty);
            empty.setVisibility(View.VISIBLE);

            mListView = (ListView) findViewById(R.id.resolver_list);
            mListView.setVisibility(View.GONE);
        }
        // Prevent the Resolver window from becoming the top fullscreen window and thus from taking
        // control of the system bars.
        getWindow().clearFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR);

        final ResolverDrawerLayout rdl = (ResolverDrawerLayout) findViewById(R.id.contentPanel);
        if (rdl != null) {
            rdl.setOnDismissedListener(new ResolverDrawerLayout.OnDismissedListener() {
                @Override
                public void onDismissed() {
                    finish();
                }
            });
        }

        if (title == null) {
            title = getTitleForAction(intent.getAction(), defaultTitleRes);
        }
        if (!TextUtils.isEmpty(title)) {
            final TextView titleView = (TextView) findViewById(R.id.title);
            if (titleView != null) {
                titleView.setText(title);
            }
            setTitle(title);
        }

        final ImageView iconView = (ImageView) findViewById(R.id.icon);
        final DisplayResolveInfo iconInfo = mAdapter.getFilteredItem();
        if (iconView != null && iconInfo != null) {
            new LoadIconIntoViewTask(iconView).execute(iconInfo);
        }

        if (alwaysUseOption || mAdapter.hasFilteredItem()) {
            final ViewGroup buttonLayout = (ViewGroup) findViewById(R.id.button_bar);
            if (buttonLayout != null) {
                buttonLayout.setVisibility(View.VISIBLE);
                mAlwaysButton = (Button) buttonLayout.findViewById(R.id.button_always);
                mOnceButton = (Button) buttonLayout.findViewById(R.id.button_once);
            } else {
                mAlwaysUseOption = false;
            }
        }

        if (mAdapter.hasFilteredItem()) {
            setAlwaysButtonEnabled(true, mAdapter.getFilteredPosition(), false);
            mOnceButton.setEnabled(true);
        }

        mProfileView = findViewById(R.id.profile_button);
        if (mProfileView != null) {
            mProfileView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    final DisplayResolveInfo dri = mAdapter.getOtherProfile();
                    if (dri == null) {
                        return;
                    }

                    final Intent intent = intentForDisplayResolveInfo(dri);
                    onIntentSelected(dri.ri, intent, false);
                    finish();
                }
            });
            bindProfileView();
        }
    
protected voidonIntentSelected(android.content.pm.ResolveInfo ri, android.content.Intent intent, boolean alwaysCheck)

        if ((mAlwaysUseOption || mAdapter.hasFilteredItem()) && mAdapter.mOrigResolveList != null) {
            // Build a reasonable intent filter, based on what matched.
            IntentFilter filter = new IntentFilter();

            if (intent.getAction() != null) {
                filter.addAction(intent.getAction());
            }
            Set<String> categories = intent.getCategories();
            if (categories != null) {
                for (String cat : categories) {
                    filter.addCategory(cat);
                }
            }
            filter.addCategory(Intent.CATEGORY_DEFAULT);

            int cat = ri.match&IntentFilter.MATCH_CATEGORY_MASK;
            Uri data = intent.getData();
            if (cat == IntentFilter.MATCH_CATEGORY_TYPE) {
                String mimeType = intent.resolveType(this);
                if (mimeType != null) {
                    try {
                        filter.addDataType(mimeType);
                    } catch (IntentFilter.MalformedMimeTypeException e) {
                        Log.w("ResolverActivity", e);
                        filter = null;
                    }
                }
            }
            if (data != null && data.getScheme() != null) {
                // We need the data specification if there was no type,
                // OR if the scheme is not one of our magical "file:"
                // or "content:" schemes (see IntentFilter for the reason).
                if (cat != IntentFilter.MATCH_CATEGORY_TYPE
                        || (!"file".equals(data.getScheme())
                                && !"content".equals(data.getScheme()))) {
                    filter.addDataScheme(data.getScheme());

                    // Look through the resolved filter to determine which part
                    // of it matched the original Intent.
                    Iterator<PatternMatcher> pIt = ri.filter.schemeSpecificPartsIterator();
                    if (pIt != null) {
                        String ssp = data.getSchemeSpecificPart();
                        while (ssp != null && pIt.hasNext()) {
                            PatternMatcher p = pIt.next();
                            if (p.match(ssp)) {
                                filter.addDataSchemeSpecificPart(p.getPath(), p.getType());
                                break;
                            }
                        }
                    }
                    Iterator<IntentFilter.AuthorityEntry> aIt = ri.filter.authoritiesIterator();
                    if (aIt != null) {
                        while (aIt.hasNext()) {
                            IntentFilter.AuthorityEntry a = aIt.next();
                            if (a.match(data) >= 0) {
                                int port = a.getPort();
                                filter.addDataAuthority(a.getHost(),
                                        port >= 0 ? Integer.toString(port) : null);
                                break;
                            }
                        }
                    }
                    pIt = ri.filter.pathsIterator();
                    if (pIt != null) {
                        String path = data.getPath();
                        while (path != null && pIt.hasNext()) {
                            PatternMatcher p = pIt.next();
                            if (p.match(path)) {
                                filter.addDataPath(p.getPath(), p.getType());
                                break;
                            }
                        }
                    }
                }
            }

            if (filter != null) {
                final int N = mAdapter.mOrigResolveList.size();
                ComponentName[] set = new ComponentName[N];
                int bestMatch = 0;
                for (int i=0; i<N; i++) {
                    ResolveInfo r = mAdapter.mOrigResolveList.get(i);
                    set[i] = new ComponentName(r.activityInfo.packageName,
                            r.activityInfo.name);
                    if (r.match > bestMatch) bestMatch = r.match;
                }
                if (alwaysCheck) {
                    getPackageManager().addPreferredActivity(filter, bestMatch, set,
                            intent.getComponent());
                } else {
                    try {
                        AppGlobals.getPackageManager().setLastChosenActivity(intent,
                                intent.resolveTypeIfNeeded(getContentResolver()),
                                PackageManager.MATCH_DEFAULT_ONLY,
                                filter, bestMatch, intent.getComponent());
                    } catch (RemoteException re) {
                        Log.d(TAG, "Error calling setLastChosenActivity\n" + re);
                    }
                }
            }
        }

        if (intent != null) {
            safelyStartActivity(intent);
        }
    
public voidonItemClick(android.widget.AdapterView parent, android.view.View view, int position, long id)

        position -= mListView.getHeaderViewsCount();
        if (position < 0) {
            // Header views don't count.
            return;
        }
        ResolveInfo resolveInfo = mAdapter.resolveInfoForPosition(position, true);
        if (mResolvingHome && hasManagedProfile()
                && !supportsManagedProfiles(resolveInfo)) {
            Toast.makeText(this, String.format(getResources().getString(
                    com.android.internal.R.string.activity_resolver_work_profiles_support),
                    resolveInfo.activityInfo.loadLabel(getPackageManager()).toString()),
                    Toast.LENGTH_LONG).show();
            return;
        }
        final int checkedPos = mListView.getCheckedItemPosition();
        final boolean hasValidSelection = checkedPos != ListView.INVALID_POSITION;
        if (mAlwaysUseOption && (!hasValidSelection || mLastSelected != checkedPos)) {
            setAlwaysButtonEnabled(hasValidSelection, checkedPos, true);
            mOnceButton.setEnabled(hasValidSelection);
            if (hasValidSelection) {
                mListView.smoothScrollToPosition(checkedPos);
            }
            mLastSelected = checkedPos;
        } else {
            startSelected(position, false, true);
        }
    
protected voidonRestart()

        super.onRestart();
        if (!mRegistered) {
            mPackageMonitor.register(this, getMainLooper(), false);
            mRegistered = true;
        }
        mAdapter.handlePackagesChanged();
        if (mProfileView != null) {
            bindProfileView();
        }
    
protected voidonRestoreInstanceState(android.os.Bundle savedInstanceState)

        super.onRestoreInstanceState(savedInstanceState);
        if (mAlwaysUseOption) {
            final int checkedPos = mListView.getCheckedItemPosition();
            final boolean hasValidSelection = checkedPos != ListView.INVALID_POSITION;
            mLastSelected = checkedPos;
            setAlwaysButtonEnabled(hasValidSelection, checkedPos, true);
            mOnceButton.setEnabled(hasValidSelection);
            if (hasValidSelection) {
                mListView.setSelection(checkedPos);
            }
        }
    
protected voidonStop()

        super.onStop();
        if (mRegistered) {
            mPackageMonitor.unregister();
            mRegistered = false;
        }
        if ((getIntent().getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
            // This resolver is in the unusual situation where it has been
            // launched at the top of a new task.  We don't let it be added
            // to the recent tasks shown to the user, and we need to make sure
            // that each time we are launched we get the correct launching
            // uid (not re-using the same resolver from an old launching uid),
            // so we will now finish ourself since being no longer visible,
            // the user probably can't get back to us.
            if (!isChangingConfigurations()) {
                finish();
            }
        }
    
public voidsafelyStartActivity(android.content.Intent intent)

        // If needed, show that intent is forwarded
        // from managed profile to owner or other way around.
        if (mProfileSwitchMessageId != -1) {
            Toast.makeText(this, getString(mProfileSwitchMessageId), Toast.LENGTH_LONG).show();
        }
        if (!mSafeForwardingMode) {
            startActivity(intent);
            onActivityStarted(intent);
            return;
        }
        try {
            startActivityAsCaller(intent, null, UserHandle.USER_NULL);
            onActivityStarted(intent);
        } catch (RuntimeException e) {
            String launchedFromPackage;
            try {
                launchedFromPackage = ActivityManagerNative.getDefault().getLaunchedFromPackage(
                        getActivityToken());
            } catch (RemoteException e2) {
                launchedFromPackage = "??";
            }
            Slog.wtf(TAG, "Unable to launch as uid " + mLaunchedFromUid
                    + " package " + launchedFromPackage + ", while running in "
                    + ActivityThread.currentProcessName(), e);
        }
    
private voidsetAlwaysButtonEnabled(boolean hasValidSelection, int checkedPos, boolean filtered)

        boolean enabled = false;
        if (hasValidSelection) {
            ResolveInfo ri = mAdapter.resolveInfoForPosition(checkedPos, filtered);
            if (ri.targetUserId == UserHandle.USER_CURRENT) {
                enabled = true;
            }
        }
        mAlwaysButton.setEnabled(enabled);
    
private voidsetProfileSwitchMessageId(int contentUserHint)

        if (contentUserHint != UserHandle.USER_CURRENT &&
                contentUserHint != UserHandle.myUserId()) {
            UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
            UserInfo originUserInfo = userManager.getUserInfo(contentUserHint);
            boolean originIsManaged = originUserInfo != null ? originUserInfo.isManagedProfile()
                    : false;
            boolean targetIsManaged = userManager.isManagedProfile();
            if (originIsManaged && !targetIsManaged) {
                mProfileSwitchMessageId = com.android.internal.R.string.forward_intent_to_owner;
            } else if (!originIsManaged && targetIsManaged) {
                mProfileSwitchMessageId = com.android.internal.R.string.forward_intent_to_work;
            }
        }
    
public voidsetSafeForwardingMode(boolean safeForwarding)
Turn on launch mode that is safe to use when forwarding intents received from applications and running in system processes. This mode uses Activity.startActivityAsCaller instead of the normal Activity.startActivity for launching the activity selected by the user.

This mode is set to true by default if the activity is initialized through {@link #onCreate(android.os.Bundle)}. If a subclass calls one of the other onCreate methods, it is set to false by default. You must set it before calling one of the more detailed onCreate methods, so that it will be set correctly in the case where there is only one intent to resolve and it is thus started immediately.

        mSafeForwardingMode = safeForwarding;
    
voidshowAppDetails(android.content.pm.ResolveInfo ri)

        Intent in = new Intent().setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                .setData(Uri.fromParts("package", ri.activityInfo.packageName, null))
                .addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
        startActivity(in);
    
voidstartSelected(int which, boolean always, boolean filtered)

        if (isFinishing()) {
            return;
        }
        ResolveInfo ri = mAdapter.resolveInfoForPosition(which, filtered);
        Intent intent = mAdapter.intentForPosition(which, filtered);
        onIntentSelected(ri, intent, always);
        finish();
    
private booleansupportsManagedProfiles(android.content.pm.ResolveInfo resolveInfo)

        try {
            ApplicationInfo appInfo = getPackageManager().getApplicationInfo(
                    resolveInfo.activityInfo.packageName, 0 /* default flags */);
            return versionNumberAtLeastL(appInfo.targetSdkVersion);
        } catch (NameNotFoundException e) {
            return false;
        }
    
private booleanversionNumberAtLeastL(int versionNumber)

        return versionNumber >= Build.VERSION_CODES.LOLLIPOP;