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

Commit b8abd8d8 authored by Jason Monk's avatar Jason Monk Committed by Android (Google) Code Review
Browse files

Merge changes I8953967a,If17eddad into oc-dev

* changes:
  Add go to web action for instant apps
  Fix when instant app notif is showing
parents 8079a69e 697b82a4
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -1988,6 +1988,9 @@
    <!-- Action label for launching app info on the specified app [CHAR LIMIT=20] -->
    <string name="app_info">App info</string>

    <!-- Action label for switching to web for an instant app [CHAR LIMIT=20] -->
    <string name="go_to_web">Go to web</string>

    <!-- Quick settings tile for toggling mobile data [CHAR LIMIT=20] -->
    <string name="mobile_data">Mobile data</string>

+69 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 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;

import android.os.RemoteException;
import android.util.Log;
import android.view.IDockedStackListener;
import android.view.WindowManagerGlobal;

import java.util.function.Consumer;

/**
 * Utility wrapper to listen for whether or not a docked stack exists, to be
 * used for things like the different overview icon in that mode.
 */
public class DockedStackExistsListener extends IDockedStackListener.Stub {

    private static final String TAG = "DockedStackExistsListener";

    private final Consumer<Boolean> mCallback;

    private DockedStackExistsListener(Consumer<Boolean> callback) {
        mCallback = callback;
    }

    @Override
    public void onDividerVisibilityChanged(boolean visible) throws RemoteException {
    }

    @Override
    public void onDockedStackExistsChanged(final boolean exists) throws RemoteException {
        mCallback.accept(exists);
    }

    @Override
    public void onDockedStackMinimizedChanged(boolean minimized, long animDuration,
                                              boolean isHomeStackResizable) throws RemoteException {
    }

    @Override
    public void onAdjustedForImeChanged(boolean adjustedForIme, long animDuration)
            throws RemoteException {
    }

    @Override
    public void onDockSideChanged(int newDockSide) throws RemoteException {
    }

    public static void register(Consumer<Boolean> callback) {
        try {
            WindowManagerGlobal.getWindowManagerService().registerDockedStackListener(
                    new DockedStackExistsListener(callback));
        } catch (RemoteException e) {
            Log.e(TAG, "Failed registering docked stack exists listener", e);
        }
    }
}
+5 −34
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ import android.view.inputmethod.InputMethodManager;
import android.widget.FrameLayout;

import com.android.systemui.Dependency;
import com.android.systemui.DockedStackExistsListener;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
import com.android.systemui.plugins.PluginListener;
@@ -566,40 +567,10 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav

        getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);

        try {
            WindowManagerGlobal.getWindowManagerService().registerDockedStackListener(new Stub() {
                @Override
                public void onDividerVisibilityChanged(boolean visible) throws RemoteException {
                }

                @Override
                public void onDockedStackExistsChanged(final boolean exists) throws RemoteException {
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
        DockedStackExistsListener.register(exists -> mHandler.post(() -> {
            mDockedStackExists = exists;
            updateRecentsIcon();
                        }
                    });
                }

                @Override
                public void onDockedStackMinimizedChanged(boolean minimized, long animDuration,
                        boolean isHomeStackResizable) throws RemoteException {
                }

                @Override
                public void onAdjustedForImeChanged(boolean adjustedForIme, long animDuration)
                        throws RemoteException {
                }

                @Override
                public void onDockSideChanged(int newDockSide) throws RemoteException {
                }
            });
        } catch (RemoteException e) {
            Log.e(TAG, "Failed registering docked stack exists listener", e);
        }
        }));
    }

    void updateRotatedViews() {
+80 −18
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.SynchronousUserSwitchObserver;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -50,11 +51,11 @@ import android.telecom.TelecomManager;
import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;

import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.telephony.IccCardConstants;
import com.android.internal.telephony.TelephonyIntents;
import com.android.systemui.Dependency;
import com.android.systemui.DockedStackExistsListener;
import com.android.systemui.R;
import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.qs.tiles.DndTile;
@@ -82,6 +83,8 @@ import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.util.NotificationChannels;

import java.util.List;

/**
 * This class contains all of the policy about which icons are installed in the status
 * bar at boot time.  It goes through the normal API for icons, even though it probably
@@ -94,6 +97,7 @@ public class PhoneStatusBarPolicy implements Callback, Callbacks,
    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);

    public static final int LOCATION_STATUS_ICON_ID = R.drawable.stat_sys_location;
    public static final int NUM_TASKS_FOR_INSTANT_APP_INFO = 5;

    private final String mSlotCast;
    private final String mSlotHotspot;
@@ -132,6 +136,7 @@ public class PhoneStatusBarPolicy implements Callback, Callbacks,
    private boolean mZenVisible;
    private boolean mVolumeVisible;
    private boolean mCurrentUserSetup;
    private boolean mDockedStackExists;

    private boolean mManagedProfileIconVisible = false;
    private boolean mManagedProfileInQuietMode = false;
@@ -248,6 +253,10 @@ public class PhoneStatusBarPolicy implements Callback, Callbacks,
                noMan.cancel(notification.getTag(), notification.getId());
            }
        }
        DockedStackExistsListener.register(exists -> {
            mDockedStackExists = exists;
            updateForegroundInstantApps();
        });
    }

    public void destroy() {
@@ -495,13 +504,32 @@ public class PhoneStatusBarPolicy implements Callback, Callbacks,
        IPackageManager pm = AppGlobals.getPackageManager();
        mCurrentNotifs.clear();
        try {
            ArraySet<Integer> stacksToCheck = new ArraySet<>();
            int[] STACKS_TO_CHECK = new int[]{
                    StackId.FULLSCREEN_WORKSPACE_STACK_ID,
                    StackId.DOCKED_STACK_ID,
            };
            for (int i = 0; i < STACKS_TO_CHECK.length; i++) {
                StackInfo info = ActivityManager.getService().getStackInfo(STACKS_TO_CHECK[i]);
                if (info == null || info.topActivity == null) continue;
            int focusedId = ActivityManager.getService().getFocusedStackId();
            if (focusedId == StackId.FULLSCREEN_WORKSPACE_STACK_ID
                    || focusedId == StackId.FULLSCREEN_WORKSPACE_STACK_ID) {
                checkStack(StackId.FULLSCREEN_WORKSPACE_STACK_ID, notifs, noMan, pm);
            }
            if (mDockedStackExists) {
                checkStack(StackId.DOCKED_STACK_ID, notifs, noMan, pm);
            }
        } catch (RemoteException e) {
            e.rethrowFromSystemServer();
        }
        // Cancel all the leftover notifications that don't have a foreground process anymore.
        notifs.forEach(v -> noMan.cancelAsUser(v.first, SystemMessage.NOTE_INSTANT_APPS,
                new UserHandle(v.second)));
    }

    private void checkStack(int stackId, ArraySet<Pair<String, Integer>> notifs,
            NotificationManager noMan, IPackageManager pm) {
        try {
            StackInfo info = ActivityManager.getService().getStackInfo(stackId);
            if (info == null || info.topActivity == null) return;
            String pkg = info.topActivity.getPackageName();
            if (!hasNotif(notifs, pkg, info.userId)) {
                // TODO: Optimize by not always needing to get application info.
@@ -509,20 +537,16 @@ public class PhoneStatusBarPolicy implements Callback, Callbacks,
                ApplicationInfo appInfo = pm.getApplicationInfo(pkg,
                        PackageManager.MATCH_UNINSTALLED_PACKAGES, info.userId);
                if (appInfo.isInstantApp()) {
                        postEphemeralNotif(pkg, info.userId, appInfo, noMan);
                    }
                    postEphemeralNotif(pkg, info.userId, appInfo, noMan, info.taskIds[info.taskIds.length - 1]);
                }
            }
        } catch (RemoteException e) {
            e.rethrowFromSystemServer();
        }
        // Cancel all the leftover notifications that don't have a foreground process anymore.
        notifs.forEach(v -> noMan.cancelAsUser(v.first, SystemMessage.NOTE_INSTANT_APPS,
                new UserHandle(v.second)));
    }

    private void postEphemeralNotif(String pkg, int userId, ApplicationInfo appInfo,
            NotificationManager noMan) {
            NotificationManager noMan, int taskId) {
        final Bundle extras = new Bundle();
        extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
                mContext.getString(R.string.instant_apps));
@@ -531,12 +555,39 @@ public class PhoneStatusBarPolicy implements Callback, Callbacks,
        PendingIntent appInfoAction = PendingIntent.getActivity(mContext, 0,
                new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                        .setData(Uri.fromParts("package", pkg, null)), 0);
        // TODO: Add action for go to web as well.
        Action action = new Notification.Action.Builder(null, mContext.getString(R.string.app_info),
                appInfoAction).build();

        noMan.notifyAsUser(pkg, SystemMessage.NOTE_INSTANT_APPS,
                new Notification.Builder(mContext, NotificationChannels.GENERAL)
        Intent browserIntent = getTaskIntent(taskId, userId);
        Notification.Builder builder = new Notification.Builder(mContext, NotificationChannels.GENERAL);
        if (browserIntent != null) {
            PendingIntent pendingIntent = PendingIntent.getActivity(mContext,
                    0 /* requestCode */, browserIntent, 0 /* flags */);
            browserIntent.setComponent(null);
            browserIntent.addFlags(Intent.FLAG_IGNORE_EPHEMERAL);
            browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

            ComponentName aiaComponent = null;
            try {
                aiaComponent = AppGlobals.getPackageManager().getInstantAppInstallerComponent();
            } catch (RemoteException e) {
                e.rethrowFromSystemServer();
            }
            Intent goToWebIntent = new Intent()
                    .setComponent(aiaComponent)
                    .setAction(Intent.ACTION_VIEW)
                    .addCategory(Intent.CATEGORY_BROWSABLE)
                    .putExtra(Intent.EXTRA_PACKAGE_NAME, appInfo.packageName)
                    .putExtra(Intent.EXTRA_VERSION_CODE, appInfo.versionCode)
                    .putExtra(Intent.EXTRA_EPHEMERAL_FAILURE, pendingIntent);

            PendingIntent webPendingIntent = PendingIntent.getActivity(mContext, 0, goToWebIntent, 0);
            Action webAction = new Notification.Action.Builder(null, mContext.getString(R.string.go_to_web),
                    webPendingIntent).build();
            builder.addAction(webAction);
        }

        noMan.notifyAsUser(pkg, SystemMessage.NOTE_INSTANT_APPS, builder
                        .addExtras(extras)
                        .addAction(action)
                        .setContentIntent(appInfoAction)
@@ -551,6 +602,17 @@ public class PhoneStatusBarPolicy implements Callback, Callbacks,
                new UserHandle(userId));
    }

    private Intent getTaskIntent(int taskId, int userId) {
        List<ActivityManager.RecentTaskInfo> tasks = mContext.getSystemService(ActivityManager.class)
                .getRecentTasksForUser(NUM_TASKS_FOR_INSTANT_APP_INFO, 0, userId);
        for (int i = 0; i < tasks.size(); i++) {
            if (tasks.get(i).id == taskId) {
                return tasks.get(i).baseIntent;
            }
        }
        return null;
    }

    private boolean hasNotif(ArraySet<Pair<String, Integer>> notifs, String pkg, int userId) {
        Pair<String, Integer> key = new Pair<>(pkg, userId);
        if (notifs.remove(key)) {