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

Commit 70a2cbd0 authored by Vadim Tryshev's avatar Vadim Tryshev Committed by Android (Google) Code Review
Browse files

Merge "Storing and using user id for pinned shelf apps."

parents a76361a4 c5f860ce
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -1129,4 +1129,7 @@
    <!-- Dialog asking if the tuner should really be removed from settings [CHAR LIMIT=NONE]-->
    <!-- Dialog asking if the tuner should really be removed from settings [CHAR LIMIT=NONE]-->
    <string name="remove_from_settings_prompt">Remove System UI Tuner from Settings and stop using all of its features?"</string>
    <string name="remove_from_settings_prompt">Remove System UI Tuner from Settings and stop using all of its features?"</string>


    <!-- Displayed when user launches an app that was uninstalled  [CHAR LIMIT=NONE] -->
    <string name="activity_not_found">Application is not installed on your device</string>

</resources>
</resources>
+45 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.statusbar.phone;

import android.content.ComponentName;

/**
 * Navigation bar app information.
 */
class AppInfo {
    /**
     * Unspecified serial number for the app's user.
     */
    public static final long USER_UNSPECIFIED = -1;

    private final ComponentName mComponentName;
    private final long mUserSerialNumber;

    public AppInfo(ComponentName componentName, long userSerialNumber) {
        mComponentName = componentName;
        mUserSerialNumber = userSerialNumber;
    }

    public ComponentName getComponentName() {
        return mComponentName;
    }

    public long getUserSerialNumber() {
        return mUserSerialNumber;
    }
}
+107 −28
Original line number Original line Diff line number Diff line
@@ -18,19 +18,26 @@ package com.android.systemui.statusbar.phone;


import android.animation.LayoutTransition;
import android.animation.LayoutTransition;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.ActivityOptions;
import android.app.AppGlobals;
import android.content.ClipData;
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.ClipDescription;
import android.content.ComponentName;
import android.content.ComponentName;
import android.content.Context;
import android.content.Context;
import android.content.Intent;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.LauncherApps;
import android.content.pm.ActivityInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.Rect;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.AttributeSet;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Slog;
import android.util.Slog;
import android.view.DragEvent;
import android.view.DragEvent;
import android.view.LayoutInflater;
import android.view.LayoutInflater;
@@ -38,9 +45,12 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.LinearLayout;
import android.widget.Toast;


import com.android.systemui.R;
import com.android.systemui.R;


import java.util.List;

/**
/**
 * Container for application icons that appear in the navigation bar. Their appearance is similar
 * Container for application icons that appear in the navigation bar. Their appearance is similar
 * to the launcher hotseat. Clicking an icon launches the associated activity. A long click will
 * to the launcher hotseat. Clicking an icon launches the associated activity. A long click will
@@ -51,11 +61,15 @@ class NavigationBarApps extends LinearLayout {
    private final static boolean DEBUG = false;
    private final static boolean DEBUG = false;
    private final static String TAG = "NavigationBarApps";
    private final static String TAG = "NavigationBarApps";


    /**
     * Intent extra to store user serial number.
     */
    static final String EXTRA_PROFILE = "profile";

    // There are separate NavigationBarApps view instances for landscape vs. portrait, but they
    // There are separate NavigationBarApps view instances for landscape vs. portrait, but they
    // share the data model.
    // share the data model.
    private static NavigationBarAppsModel sAppsModel;
    private static NavigationBarAppsModel sAppsModel;


    private final LauncherApps mLauncherApps;
    private final PackageManager mPackageManager;
    private final PackageManager mPackageManager;
    private final LayoutInflater mLayoutInflater;
    private final LayoutInflater mLayoutInflater;


@@ -74,7 +88,6 @@ class NavigationBarApps extends LinearLayout {
            sAppsModel = new NavigationBarAppsModel(context);
            sAppsModel = new NavigationBarAppsModel(context);
            sAppsModel.initialize();  // Load the saved icons, if any.
            sAppsModel.initialize();  // Load the saved icons, if any.
        }
        }
        mLauncherApps = (LauncherApps) context.getSystemService("launcherapps");
        mPackageManager = context.getPackageManager();
        mPackageManager = context.getPackageManager();
        mLayoutInflater = LayoutInflater.from(context);
        mLayoutInflater = LayoutInflater.from(context);


@@ -121,12 +134,12 @@ class NavigationBarApps extends LinearLayout {
            ImageView button = createAppButton();
            ImageView button = createAppButton();
            addView(button);
            addView(button);


            ComponentName activityName = sAppsModel.getApp(i);
            AppInfo app = sAppsModel.getApp(i);
            CharSequence appLabel = getAppLabel(mPackageManager, activityName);
            CharSequence appLabel = getAppLabel(mPackageManager, app.getComponentName());
            button.setContentDescription(getAppLabel(mPackageManager, activityName));
            button.setContentDescription(appLabel);


            // Load the icon asynchronously.
            // Load the icon asynchronously.
            new GetActivityIconTask(mPackageManager, button).execute(activityName);
            new GetActivityIconTask(mPackageManager, button).execute(app.getComponentName());
        }
        }
    }
    }


@@ -150,8 +163,8 @@ class NavigationBarApps extends LinearLayout {
        public boolean onLongClick(View v) {
        public boolean onLongClick(View v) {
            mDragView = v;
            mDragView = v;
            ImageView icon = (ImageView) v;
            ImageView icon = (ImageView) v;
            ComponentName activityName = sAppsModel.getApp(indexOfChild(v));
            AppInfo app = sAppsModel.getApp(indexOfChild(v));
            startAppDrag(icon, activityName);
            startAppDrag(icon, app);
            return true;
            return true;
        }
        }
    }
    }
@@ -175,9 +188,13 @@ class NavigationBarApps extends LinearLayout {
    }
    }


    /** Helper function to start dragging an app icon (either pinned or recent). */
    /** Helper function to start dragging an app icon (either pinned or recent). */
    static void startAppDrag(ImageView icon, ComponentName activityName) {
    static void startAppDrag(ImageView icon, AppInfo appInfo) {
        // The drag data is an Intent to launch the activity.
        // The drag data is an Intent to launch the activity.
        Intent mainIntent = Intent.makeMainActivity(activityName);
        Intent mainIntent = Intent.makeMainActivity(appInfo.getComponentName());
        long userSerialNumber = appInfo.getUserSerialNumber();
        if (userSerialNumber != AppInfo.USER_UNSPECIFIED) {
            mainIntent.putExtra(EXTRA_PROFILE, userSerialNumber);
        }
        ClipData dragData = ClipData.newIntent("", mainIntent);
        ClipData dragData = ClipData.newIntent("", mainIntent);
        // Use the ImageView to create the shadow.
        // Use the ImageView to create the shadow.
        View.DragShadowBuilder shadow = new AppIconDragShadowBuilder(icon);
        View.DragShadowBuilder shadow = new AppIconDragShadowBuilder(icon);
@@ -294,7 +311,7 @@ class NavigationBarApps extends LinearLayout {
        addView(mDragView, targetIndex);
        addView(mDragView, targetIndex);


        // Update the data model.
        // Update the data model.
        ComponentName app = sAppsModel.removeApp(dragViewIndex);
        AppInfo app = sAppsModel.removeApp(dragViewIndex);
        sAppsModel.addApp(targetIndex, app);
        sAppsModel.addApp(targetIndex, app);
    }
    }


@@ -314,15 +331,15 @@ class NavigationBarApps extends LinearLayout {
        }
        }


        // The drag view was a placeholder. Unpack the drop.
        // The drag view was a placeholder. Unpack the drop.
        ComponentName activityName = getActivityNameFromDragEvent(event);
        AppInfo appInfo = getAppFromDragEvent(event);
        if (activityName == null) {
        if (appInfo == null) {
            // This wasn't a valid drop. Clean up the placeholder and model.
            // This wasn't a valid drop. Clean up the placeholder and model.
            removePlaceholderDragViewIfNeeded();
            removePlaceholderDragViewIfNeeded();
            return true;
            return false;
        }
        }


        // The drop had valid data. Update the placeholder with a real activity and icon.
        // The drop had valid data. Update the placeholder with a real activity and icon.
        updateAppAt(dragViewIndex, activityName);
        updateAppAt(dragViewIndex, appInfo);
        endDrag();
        endDrag();
        return true;
        return true;
    }
    }
@@ -334,8 +351,8 @@ class NavigationBarApps extends LinearLayout {
        sAppsModel.savePrefs();
        sAppsModel.savePrefs();
    }
    }


    /** Returns an app launch Intent from a DragEvent, or null if the data wasn't valid. */
    /** Returns an app info from a DragEvent, or null if the data wasn't valid. */
    private ComponentName getActivityNameFromDragEvent(DragEvent event) {
    private AppInfo getAppFromDragEvent(DragEvent event) {
        ClipData data = event.getClipData();
        ClipData data = event.getClipData();
        if (data == null) {
        if (data == null) {
            return null;
            return null;
@@ -347,14 +364,16 @@ class NavigationBarApps extends LinearLayout {
        if (intent == null) {
        if (intent == null) {
            return null;
            return null;
        }
        }
        return intent.getComponent();

        long userSerialNumber = intent.getLongExtra(EXTRA_PROFILE, AppInfo.USER_UNSPECIFIED);
        return new AppInfo(intent.getComponent(), userSerialNumber);
    }
    }


    /** Updates the app at a given view index. */
    /** Updates the app at a given view index. */
    private void updateAppAt(int index, ComponentName activityName) {
    private void updateAppAt(int index, AppInfo appInfo) {
        sAppsModel.setApp(index, activityName);
        sAppsModel.setApp(index, appInfo);
        ImageView button = (ImageView) getChildAt(index);
        ImageView button = (ImageView) getChildAt(index);
        new GetActivityIconTask(mPackageManager, button).execute(activityName);
        new GetActivityIconTask(mPackageManager, button).execute(appInfo.getComponentName());
    }
    }


    /** Removes the empty placeholder view and cleans up the data model. */
    /** Removes the empty placeholder view and cleans up the data model. */
@@ -411,11 +430,26 @@ class NavigationBarApps extends LinearLayout {
    private class AppClickListener implements View.OnClickListener {
    private class AppClickListener implements View.OnClickListener {
        @Override
        @Override
        public void onClick(View v) {
        public void onClick(View v) {
            ComponentName activityName = sAppsModel.getApp(indexOfChild(v));
            AppInfo appInfo = sAppsModel.getApp(indexOfChild(v));
            ComponentName component = appInfo.getComponentName();

            UserManager userManager =
                    (UserManager) getContext().getSystemService(Context.USER_SERVICE);


            // TODO: Support apps from multiple user profiles. The profile will need to be stored in
            long appUserSerialNumber = appInfo.getUserSerialNumber();
            // the data model for each app shortcut.

            UserHandle user = UserHandle.OWNER;
            UserHandle appUser = null;
            if (appUserSerialNumber != AppInfo.USER_UNSPECIFIED) {
                appUser = userManager.getUserForSerialNumber(appUserSerialNumber);
            }

            int appUserId;
            if (appUser != null) {
                appUserId = appUser.getIdentifier();
            } else {
                appUserId = ActivityManager.getCurrentUser();
                appUser = new UserHandle(appUserId);
            }


            // Play a scale-up animation while launching the activity.
            // Play a scale-up animation while launching the activity.
            // TODO: Consider playing a different animation, or no animation, if the activity is
            // TODO: Consider playing a different animation, or no animation, if the activity is
@@ -427,8 +461,53 @@ class NavigationBarApps extends LinearLayout {
                    ActivityOptions.makeScaleUpAnimation(v, 0, 0, v.getWidth(), v.getHeight());
                    ActivityOptions.makeScaleUpAnimation(v, 0, 0, v.getWidth(), v.getHeight());
            Bundle optsBundle = opts.toBundle();
            Bundle optsBundle = opts.toBundle();


            // Launch the activity.
            // Launch the activity. This code is based on LauncherAppsService.startActivityAsUser code.
            mLauncherApps.startMainActivity(activityName, user, sourceBounds, optsBundle);
            Intent launchIntent = new Intent(Intent.ACTION_MAIN);
            launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
            launchIntent.setSourceBounds(sourceBounds);
            launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            launchIntent.setPackage(component.getPackageName());

            IPackageManager pm = AppGlobals.getPackageManager();
            try {
                ActivityInfo info = pm.getActivityInfo(component, 0, appUserId);
                if (info == null) {
                    Toast.makeText(getContext(), R.string.activity_not_found, Toast.LENGTH_SHORT).show();
                    Log.e(TAG, "Can't start activity " + component + " because it's not installed.");
                    return;
                }

                if (!info.exported) {
                    Toast.makeText(getContext(), R.string.activity_not_found, Toast.LENGTH_SHORT).show();
                    Log.e(TAG, "Can't start activity " + component + " because it doesn't have 'exported' attribute.");
                    return;
                }
            } catch (RemoteException e) {
                Toast.makeText(getContext(), R.string.activity_not_found, Toast.LENGTH_SHORT).show();
                Log.e(TAG, "Failed to get activity info for " + component, e);
                return;
            }

            // Check that the component actually has Intent.CATEGORY_LAUCNCHER
            // as calling startActivityAsUser ignores the category and just
            // resolves based on the component if present.
            List<ResolveInfo> apps = getContext().getPackageManager().queryIntentActivitiesAsUser(launchIntent,
                    0 /* flags */, appUserId);
            final int size = apps.size();
            for (int i = 0; i < size; ++i) {
                ActivityInfo activityInfo = apps.get(i).activityInfo;
                if (activityInfo.packageName.equals(component.getPackageName()) &&
                        activityInfo.name.equals(component.getClassName())) {
                    // Found an activity with category launcher that matches
                    // this component so ok to launch.
                    launchIntent.setComponent(component);
                    mContext.startActivityAsUser(launchIntent, optsBundle, appUser);
                    return;
                }
            }

            Toast.makeText(getContext(), R.string.activity_not_found, Toast.LENGTH_SHORT).show();
            Log.e(TAG, "Attempt to launch activity without category Intent.CATEGORY_LAUNCHER " + component);
        }
        }
    }
    }
}
}
+26 −12
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@


package com.android.systemui.statusbar.phone;
package com.android.systemui.statusbar.phone;


import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.ComponentName;
import android.content.Context;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences;
@@ -55,11 +56,14 @@ class NavigationBarAppsModel {
    // Preference name prefix for each app's info. The actual pref has an integer appended to it.
    // Preference name prefix for each app's info. The actual pref has an integer appended to it.
    private final static String APP_PREF_PREFIX = "app_";
    private final static String APP_PREF_PREFIX = "app_";


    // User serial number prefix for each app's info. The actual pref has an integer appended to it.
    private final static String APP_USER_PREFIX = "app_user_";

    private final LauncherApps mLauncherApps;
    private final LauncherApps mLauncherApps;
    private final SharedPreferences mPrefs;
    private final SharedPreferences mPrefs;


    // Apps are represented as an ordered list of component names.
    // Apps are represented as an ordered list of app infos.
    private final List<ComponentName> mApps = new ArrayList<ComponentName>();
    private final List<AppInfo> mApps = new ArrayList<AppInfo>();


    public NavigationBarAppsModel(Context context) {
    public NavigationBarAppsModel(Context context) {
        mLauncherApps = (LauncherApps) context.getSystemService("launcherapps");
        mLauncherApps = (LauncherApps) context.getSystemService("launcherapps");
@@ -97,22 +101,22 @@ class NavigationBarAppsModel {
    }
    }


    /** Returns the app at the given index. */
    /** Returns the app at the given index. */
    public ComponentName getApp(int index) {
    public AppInfo getApp(int index) {
        return mApps.get(index);
        return mApps.get(index);
    }
    }


    /** Adds the app before the given index. */
    /** Adds the app before the given index. */
    public void addApp(int index, ComponentName name) {
    public void addApp(int index, AppInfo appInfo) {
        mApps.add(index, name);
        mApps.add(index, appInfo);
    }
    }


    /** Sets the app at the given index. */
    /** Sets the app at the given index. */
    public void setApp(int index, ComponentName name) {
    public void setApp(int index, AppInfo appInfo) {
        mApps.set(index, name);
        mApps.set(index, appInfo);
    }
    }


    /** Remove the app at the given index. */
    /** Remove the app at the given index. */
    public ComponentName removeApp(int index) {
    public AppInfo removeApp(int index) {
        return mApps.remove(index);
        return mApps.remove(index);
    }
    }


@@ -125,8 +129,10 @@ class NavigationBarAppsModel {
        int appCount = mApps.size();
        int appCount = mApps.size();
        edit.putInt(APP_COUNT_PREF, appCount);
        edit.putInt(APP_COUNT_PREF, appCount);
        for (int i = 0; i < appCount; i++) {
        for (int i = 0; i < appCount; i++) {
            String componentNameString = mApps.get(i).flattenToString();
            final AppInfo appInfo = mApps.get(i);
            String componentNameString = appInfo.getComponentName().flattenToString();
            edit.putString(prefNameForApp(i), componentNameString);
            edit.putString(prefNameForApp(i), componentNameString);
            edit.putLong(prefUserForApp(i), appInfo.getUserSerialNumber());
        }
        }
        // Start an asynchronous disk write.
        // Start an asynchronous disk write.
        edit.apply();
        edit.apply();
@@ -143,7 +149,8 @@ class NavigationBarAppsModel {
                continue;
                continue;
            }
            }
            ComponentName componentName = ComponentName.unflattenFromString(prefValue);
            ComponentName componentName = ComponentName.unflattenFromString(prefValue);
            mApps.add(componentName);
            long userSerialNumber = mPrefs.getLong(prefUserForApp(i), AppInfo.USER_UNSPECIFIED);
            mApps.add(new AppInfo(componentName, userSerialNumber));
        }
        }
    }
    }


@@ -151,11 +158,12 @@ class NavigationBarAppsModel {
    private void addDefaultApps() {
    private void addDefaultApps() {
        // Get a list of all app activities.
        // Get a list of all app activities.
        List<LauncherActivityInfo> apps =
        List<LauncherActivityInfo> apps =
                mLauncherApps.getActivityList(null /* packageName */, UserHandle.OWNER);
                mLauncherApps.getActivityList(
                        null /* packageName */, new UserHandle(ActivityManager.getCurrentUser()));
        int appCount = apps.size();
        int appCount = apps.size();
        for (int i = 0; i < NUM_INITIAL_APPS && i < appCount; i++) {
        for (int i = 0; i < NUM_INITIAL_APPS && i < appCount; i++) {
            LauncherActivityInfo activityInfo = apps.get(i);
            LauncherActivityInfo activityInfo = apps.get(i);
            mApps.add(activityInfo.getComponentName());
            mApps.add(new AppInfo(activityInfo.getComponentName(), AppInfo.USER_UNSPECIFIED));
        }
        }
    }
    }


@@ -163,4 +171,10 @@ class NavigationBarAppsModel {
    private static String prefNameForApp(int index) {
    private static String prefNameForApp(int index) {
        return APP_PREF_PREFIX + Integer.toString(index);
        return APP_PREF_PREFIX + Integer.toString(index);
    }
    }

    /** Returns the pref name for the app's user at a given index. */
    private static String prefUserForApp(int index) {
        return APP_USER_PREFIX + Integer.toString(index);
    }

}
}
+1 −1
Original line number Original line Diff line number Diff line
@@ -232,7 +232,7 @@ class NavigationBarRecents extends LinearLayout {
            }
            }


            if (DEBUG) Slog.d(TAG, "Start drag with " + intent);
            if (DEBUG) Slog.d(TAG, "Start drag with " + intent);
            NavigationBarApps.startAppDrag(icon, intent.getComponent());
            NavigationBarApps.startAppDrag(icon, new AppInfo (intent.getComponent(), AppInfo.USER_UNSPECIFIED));
            return true;
            return true;
        }
        }
    }
    }
Loading