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

Commit 4b1542a4 authored by Vadim Tryshev's avatar Vadim Tryshev
Browse files

Fix accessibility labels for app icons.

Derive the app labels in a right way.
Not forgetting to get accessibility labels for newly dragged-in apps.

The change adds inefficiency with apps getting repeatedly resolved several times,
which is OK for a prototype, but I have plans to optimize this.

Bug: 20024603
Change-Id: I755d38de34c016d0ec31ecc617f7accfd876693b
parent 4dc0c15a
Loading
Loading
Loading
Loading
+20 −28
Original line number Diff line number Diff line
@@ -31,7 +31,6 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.PixelFormat;
@@ -247,7 +246,7 @@ class NavigationBarApps extends LinearLayout
            ComponentName appComponentName = appInfo.getComponentName();
            if (!appComponentName.getPackageName().equals(packageName)) continue;

            if (sAppsModel.buildAppLaunchIntent(appInfo) != null) {
            if (sAppsModel.resolveApp(appInfo) != null) {
                continue;
            }

@@ -309,15 +308,9 @@ class NavigationBarApps extends LinearLayout
    }

    private void addAppButton(AppButtonData appButtonData) {
        ImageView button = createAppButton(appButtonData);
        ImageView button = createAppButton();
        updateApp(button, appButtonData);
        addView(button);

        AppInfo app = appButtonData.appInfo;
        CharSequence appLabel = getAppLabel(mPackageManager, app.getComponentName());
        button.setContentDescription(appLabel);

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

    private List<AppInfo> getPinnedApps() {
@@ -359,7 +352,7 @@ class NavigationBarApps extends LinearLayout
    /**
     * Creates a new ImageView for an app, inflated from R.layout.navigation_bar_app_item.
     */
    private ImageView createAppButton(AppButtonData appButtonData) {
    private ImageView createAppButton() {
        ImageView button = (ImageView) mLayoutInflater.inflate(
                R.layout.navigation_bar_app_item, this, false /* attachToRoot */);
        button.setOnHoverListener(new AppHoverListener());
@@ -368,7 +361,6 @@ class NavigationBarApps extends LinearLayout
        // TODO: Ripple effect. Use either KeyButtonRipple or the default ripple background.
        button.setOnLongClickListener(new AppLongClickListener());
        button.setOnDragListener(new AppIconDragListener());
        button.setTag(appButtonData);
        return button;
    }

@@ -387,17 +379,12 @@ class NavigationBarApps extends LinearLayout
     * TODO: Cache the labels, perhaps in an LruCache.
     */
    @Nullable
    static CharSequence getAppLabel(PackageManager packageManager,
                                    ComponentName activityName) {
        String packageName = activityName.getPackageName();
        ApplicationInfo info;
        try {
            info = packageManager.getApplicationInfo(packageName, 0x0 /* flags */);
        } catch (PackageManager.NameNotFoundException e) {
            Slog.w(TAG, "Package not found " + packageName);
            return null;
        }
        return packageManager.getApplicationLabel(info);
    private CharSequence getAppLabel(AppInfo appInfo) {
        NavigationBarAppsModel.ResolvedApp resolvedApp = sAppsModel.resolveApp(appInfo);
        if (resolvedApp == null) return null;

        CharSequence unbadgedLabel = resolvedApp.ri.loadLabel(mPackageManager);
        return mUserManager.getBadgedLabelForUser(unbadgedLabel, appInfo.getUser());
    }

    /** Helper function to start dragging an app icon (either pinned or recent). */
@@ -484,7 +471,7 @@ class NavigationBarApps extends LinearLayout
     * Creates a blank icon-sized View to create an empty space during a drag.
     */
    private ImageView createPlaceholderDragView(int index) {
        ImageView button = createAppButton(null);
        ImageView button = createAppButton();
        addView(button, index);
        return button;
    }
@@ -637,7 +624,7 @@ class NavigationBarApps extends LinearLayout
            return null;
        }
        AppInfo appInfo = new AppInfo(componentName, appUser);
        if (sAppsModel.buildAppLaunchIntent(appInfo) == null) {
        if (sAppsModel.resolveApp(appInfo) == null) {
            return null;
        }
        return appInfo;
@@ -645,6 +632,9 @@ class NavigationBarApps extends LinearLayout

    /** Updates the app at a given view index. */
    private void updateApp(ImageView button, AppButtonData appButtonData) {
        CharSequence appLabel = getAppLabel(appButtonData.appInfo);
        button.setContentDescription(appLabel);

        button.setTag(appButtonData);
        new GetActivityIconTask(mPackageManager, button).execute(appButtonData);
    }
@@ -829,13 +819,15 @@ class NavigationBarApps extends LinearLayout
     */
    private class AppClickListener implements View.OnClickListener {
        private void launchApp(AppInfo appInfo, View anchor) {
            Intent launchIntent = sAppsModel.buildAppLaunchIntent(appInfo);
            if (launchIntent == null) {
            NavigationBarAppsModel.ResolvedApp resolvedApp = sAppsModel.resolveApp(appInfo);
            if (resolvedApp == null) {
                Toast.makeText(
                        getContext(), R.string.activity_not_found, Toast.LENGTH_SHORT).show();
                return;
            }

            Intent launchIntent = resolvedApp.launchIntent;

            // Play a scale-up animation while launching the activity.
            // TODO: Consider playing a different animation, or no animation, if the activity is
            // already open in a visible window. In that case we should move the task to front
@@ -1078,7 +1070,7 @@ class NavigationBarApps extends LinearLayout
        UserHandle taskUser = new UserHandle(task.userId);
        AppInfo appInfo = new AppInfo(componentName, taskUser);

        if (sAppsModel.buildAppLaunchIntent(appInfo) == null) {
        if (sAppsModel.resolveApp(appInfo) == null) {
            // If task's activity is not launcheable, fall back to a launch component of the
            // task's package.
            ComponentName component = getLaunchComponentForPackage(
+14 −5
Original line number Diff line number Diff line
@@ -48,6 +48,11 @@ class NavigationBarAppsModel {
        void onPinnedAppsChanged();
    }

    public class ResolvedApp {
        Intent launchIntent;
        ResolveInfo ri;
    }

    private final static String TAG = "NavigationBarAppsModel";

    // Default number of apps to load initially.
@@ -112,8 +117,8 @@ class NavigationBarAppsModel {
        return AppGlobals.getPackageManager();
    }

    // Returns a launch intent for a given app info, or null if the app info is unlauncheable.
    public Intent buildAppLaunchIntent(AppInfo appInfo) {
    // Returns a resolved app info for a given app info, or null if the app info is unlauncheable.
    public ResolvedApp resolveApp(AppInfo appInfo) {
        ComponentName component = appInfo.getComponentName();
        int appUserId = appInfo.getUser().getIdentifier();

@@ -160,13 +165,17 @@ class NavigationBarAppsModel {
                0 /* flags */, appUserId);
        final int size = apps.size();
        for (int i = 0; i < size; ++i) {
            ActivityInfo activityInfo = apps.get(i).activityInfo;
            ResolveInfo ri = apps.get(i);
            ActivityInfo activityInfo = ri.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);
                return launchIntent;
                ResolvedApp resolvedApp = new ResolvedApp();
                resolvedApp.launchIntent = launchIntent;
                resolvedApp.ri = ri;
                return resolvedApp;
            }
        }

@@ -300,7 +309,7 @@ class NavigationBarAppsModel {
            return null;
        }
        AppInfo appInfo = new AppInfo(componentName, appUser);
        if (buildAppLaunchIntent(appInfo) == null) {
        if (resolveApp(appInfo) == null) {
            return null;
        }
        return appInfo;
+10 −9
Original line number Diff line number Diff line
@@ -44,7 +44,6 @@ import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/** Tests for the data model for the navigation bar app icons. */
@@ -109,8 +108,8 @@ public class NavigationBarAppsModelTest extends AndroidTestCase {
        };
    }

    /** Tests buildAppLaunchIntent(). */
    public void testBuildAppLaunchIntent() {
    /** Tests resolveApp(). */
    public void testResolveApp() {
        ActivityInfo mockNonExportedActivityInfo = new ActivityInfo();
        mockNonExportedActivityInfo.exported = false;
        ActivityInfo mockExportedActivityInfo = new ActivityInfo();
@@ -149,25 +148,27 @@ public class NavigationBarAppsModelTest extends AndroidTestCase {

        mModel.setCurrentUser(3);
        // Unlauncheable (for various reasons) apps.
        assertEquals(null, mModel.buildAppLaunchIntent(
        assertEquals(null, mModel.resolveApp(
                new AppInfo(new ComponentName("package0", "class0"), new UserHandle(3))));
        mModel.setCurrentUser(4);
        assertEquals(null, mModel.buildAppLaunchIntent(
        assertEquals(null, mModel.resolveApp(
                new AppInfo(new ComponentName("package1", "class1"), new UserHandle(4))));
        mModel.setCurrentUser(5);
        assertEquals(null, mModel.buildAppLaunchIntent(
        assertEquals(null, mModel.resolveApp(
                new AppInfo(new ComponentName("package2", "class2"), new UserHandle(5))));
        mModel.setCurrentUser(6);
        assertEquals(null, mModel.buildAppLaunchIntent(
        assertEquals(null, mModel.resolveApp(
                new AppInfo(new ComponentName("package3", "class3"), new UserHandle(6))));

        // A launcheable app.
        mModel.setCurrentUser(7);
        Intent intent = mModel.buildAppLaunchIntent(
        NavigationBarAppsModel.ResolvedApp resolvedApp = mModel.resolveApp(
                new AppInfo(new ComponentName("package4", "class4"), new UserHandle(7)));
        assertNotNull(intent);
        assertNotNull(resolvedApp);
        Intent intent = resolvedApp.launchIntent;
        assertEquals(new ComponentName("package4", "class4"), intent.getComponent());
        assertEquals("package4", intent.getPackage());
        assertEquals(ri1, resolvedApp.ri);
    }

    /** Initializes the model from SharedPreferences for a few app activites. */