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

Commit eae1c34e authored by Sunny Goyal's avatar Sunny Goyal
Browse files

Making some ActivityManager API calls synchronous

Bug: 170648272
Test: Verified changes in jar with Launcher
Change-Id: I8fcf1e4bc098c70342d1bb7b8df6c407e75a74e4
parent 0afb17c6
Loading
Loading
Loading
Loading
+19 −104
Original line number Diff line number Diff line
@@ -34,8 +34,6 @@ import android.app.WindowConfiguration;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.graphics.Rect;
@@ -45,7 +43,6 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
import android.view.IRecentsAnimationController;
@@ -58,7 +55,6 @@ import com.android.systemui.shared.recents.model.ThumbnailData;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Future;
import java.util.function.Consumer;

public class ActivityManagerWrapper {
@@ -74,14 +70,7 @@ public class ActivityManagerWrapper {
    // Should match the value in AssistManager
    private static final String INVOCATION_TIME_MS_KEY = "invocation_time_ms";

    private final PackageManager mPackageManager;
    private final BackgroundExecutor mBackgroundExecutor;

    private ActivityManagerWrapper() {
        final Context context = AppGlobals.getInitialApplication();
        mPackageManager = context.getPackageManager();
        mBackgroundExecutor = BackgroundExecutor.get();
    }
    private ActivityManagerWrapper() { }

    public static ActivityManagerWrapper getInstance() {
        return sInstance;
@@ -159,9 +148,6 @@ public class ActivityManagerWrapper {
     * Removes the outdated snapshot of home task.
     */
    public void invalidateHomeTaskSnapshot(final Activity homeActivity) {
        mBackgroundExecutor.submit(new Runnable() {
            @Override
            public void run() {
        try {
            ActivityTaskManager.getService().invalidateHomeTaskSnapshot(
                    homeActivity.getActivityToken());
@@ -169,51 +155,6 @@ public class ActivityManagerWrapper {
            Log.w(TAG, "Failed to invalidate home snapshot", e);
        }
    }
        });
    }

    /**
     * @return the activity label, badging if necessary.
     */
    public String getBadgedActivityLabel(ActivityInfo info, int userId) {
        return getBadgedLabel(info.loadLabel(mPackageManager).toString(), userId);
    }

    /**
     * @return the application label, badging if necessary.
     */
    public String getBadgedApplicationLabel(ApplicationInfo appInfo, int userId) {
        return getBadgedLabel(appInfo.loadLabel(mPackageManager).toString(), userId);
    }

    /**
     * @return the content description for a given task, badging it if necessary.  The content
     * description joins the app and activity labels.
     */
    public String getBadgedContentDescription(ActivityInfo info, int userId,
            ActivityManager.TaskDescription td) {
        String activityLabel;
        if (td != null && td.getLabel() != null) {
            activityLabel = td.getLabel();
        } else {
            activityLabel = info.loadLabel(mPackageManager).toString();
        }
        String applicationLabel = info.applicationInfo.loadLabel(mPackageManager).toString();
        String badgedApplicationLabel = getBadgedLabel(applicationLabel, userId);
        return applicationLabel.equals(activityLabel)
                ? badgedApplicationLabel
                : badgedApplicationLabel + " " + activityLabel;
    }

    /**
     * @return the given label for a user, badging if necessary.
     */
    private String getBadgedLabel(String label, int userId) {
        if (userId != UserHandle.myUserId()) {
            label = mPackageManager.getUserBadgedLabel(label, new UserHandle(userId)).toString();
        }
        return label;
    }

    /**
     * Starts the recents activity. The caller should manage the thread on which this is called.
@@ -342,61 +283,35 @@ public class ActivityManagerWrapper {
    /**
     * Requests that the system close any open system windows (including other SystemUI).
     */
    public Future<?> closeSystemWindows(final String reason) {
        return mBackgroundExecutor.submit(new Runnable() {
            @Override
            public void run() {
    public void closeSystemWindows(final String reason) {
        try {
            ActivityManager.getService().closeSystemDialogs(reason);
        } catch (RemoteException e) {
            Log.w(TAG, "Failed to close system windows", e);
        }
    }
        });
    }

    /**
     * Removes a task by id.
     */
    public void removeTask(final int taskId) {
        mBackgroundExecutor.submit(new Runnable() {
            @Override
            public void run() {
        try {
            ActivityTaskManager.getService().removeTask(taskId);
        } catch (RemoteException e) {
            Log.w(TAG, "Failed to remove task=" + taskId, e);
        }
    }
        });
    }

    /**
     * Removes all the recent tasks.
     */
    public void removeAllRecentTasks() {
        mBackgroundExecutor.submit(new Runnable() {
            @Override
            public void run() {
        try {
            ActivityTaskManager.getService().removeAllVisibleRecentTasks();
        } catch (RemoteException e) {
            Log.w(TAG, "Failed to remove all tasks", e);
        }
    }
        });
    }

    /**
     * Cancels the current window transtion to/from Recents for the given task id.
     */
    public void cancelWindowTransition(int taskId) {
        try {
            ActivityTaskManager.getService().cancelTaskWindowTransition(taskId);
        } catch (RemoteException e) {
            Log.w(TAG, "Failed to cancel window transition for task=" + taskId, e);
        }
    }

    /**
     * @return whether screen pinning is active.
+0 −61
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.shared.system;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * Offloads work from other threads by running it in a background thread.
 */
public class BackgroundExecutor {

    private static final BackgroundExecutor sInstance = new BackgroundExecutor();

    private final ExecutorService mExecutorService = Executors.newFixedThreadPool(2);

    /**
     * @return the static instance of the background executor.
     */
    public static BackgroundExecutor get() {
        return sInstance;
    }

    /**
     * Runs the given {@param callable} on one of the background executor threads.
     */
    public <T> Future<T> submit(Callable<T> callable) {
        return mExecutorService.submit(callable);
    }

    /**
     * Runs the given {@param runnable} on one of the background executor threads.
     */
    public Future<?> submit(Runnable runnable) {
        return mExecutorService.submit(runnable);
    }

    /**
     * Runs the given {@param runnable} on one of the background executor threads. Return
     * {@param result} when the future is resolved.
     */
    public <T> Future<T> submit(Runnable runnable, T result) {
        return mExecutorService.submit(runnable, result);
    }
}
+0 −109
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.shared.system;

import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.RecordingCanvas;
import android.view.View;
import android.view.ViewRootImpl;
import android.view.WindowCallbacks;

public class WindowCallbacksCompat {

    private final WindowCallbacks mWindowCallbacks = new WindowCallbacks() {
        @Override
        public void onWindowSizeIsChanging(Rect newBounds, boolean fullscreen, Rect systemInsets,
                Rect stableInsets) {
            WindowCallbacksCompat.this.onWindowSizeIsChanging(newBounds, fullscreen, systemInsets,
                    stableInsets);
        }

        @Override
        public void onWindowDragResizeStart(Rect initialBounds, boolean fullscreen,
                Rect systemInsets, Rect stableInsets, int resizeMode) {
            WindowCallbacksCompat.this.onWindowDragResizeStart(initialBounds, fullscreen,
                    systemInsets, stableInsets, resizeMode);
        }

        @Override
        public void onWindowDragResizeEnd() {
            WindowCallbacksCompat.this.onWindowDragResizeEnd();
        }

        @Override
        public boolean onContentDrawn(int offsetX, int offsetY, int sizeX, int sizeY) {
            return WindowCallbacksCompat.this.onContentDrawn(offsetX, offsetY, sizeX, sizeY);
        }

        @Override
        public void onRequestDraw(boolean reportNextDraw) {
            WindowCallbacksCompat.this.onRequestDraw(reportNextDraw);
        }

        @Override
        public void onPostDraw(RecordingCanvas canvas) {
            WindowCallbacksCompat.this.onPostDraw(canvas);
        }
    };

    private final View mView;

    public WindowCallbacksCompat(View view) {
        mView = view;
    }

    public void onWindowSizeIsChanging(Rect newBounds, boolean fullscreen, Rect systemInsets,
            Rect stableInsets) { }

    public void onWindowDragResizeStart(Rect initialBounds, boolean fullscreen, Rect systemInsets,
            Rect stableInsets, int resizeMode) { }

    public void onWindowDragResizeEnd() { }

    public boolean onContentDrawn(int offsetX, int offsetY, int sizeX, int sizeY) {
        return false;
    }

    public void onRequestDraw(boolean reportNextDraw) {
        if (reportNextDraw) {
            reportDrawFinish();
        }
    }

    public void onPostDraw(Canvas canvas) { }

    public void reportDrawFinish() {
        mView.getViewRootImpl().reportDrawFinish();
    }

    public boolean attach() {
        ViewRootImpl root = mView.getViewRootImpl();
        if (root != null) {
            root.addWindowCallbacks(mWindowCallbacks);
            root.requestInvalidateRootRenderNode();
            return true;
        }
        return false;
    }

    public void detach() {
        ViewRootImpl root = mView.getViewRootImpl();
        if (root != null) {
            root.removeWindowCallbacks(mWindowCallbacks);
        }
    }
}
+1 −12
Original line number Diff line number Diff line
@@ -35,9 +35,6 @@ import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.statusbar.phone.StatusBar;

import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import javax.inject.Inject;

@@ -48,7 +45,6 @@ import javax.inject.Inject;
public class ActionProxyReceiver extends BroadcastReceiver {
    private static final String TAG = "ActionProxyReceiver";

    private static final int CLOSE_WINDOWS_TIMEOUT_MILLIS = 3000;
    private final StatusBar mStatusBar;
    private final ActivityManagerWrapper mActivityManagerWrapper;
    private final ScreenshotSmartActions mScreenshotSmartActions;
@@ -65,14 +61,7 @@ public class ActionProxyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, final Intent intent) {
        Runnable startActivityRunnable = () -> {
            try {
                mActivityManagerWrapper.closeSystemWindows(
                        SYSTEM_DIALOG_REASON_SCREENSHOT).get(
                        CLOSE_WINDOWS_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
            } catch (TimeoutException | InterruptedException | ExecutionException e) {
                Log.e(TAG, "Unable to share screenshot", e);
                return;
            }
            mActivityManagerWrapper.closeSystemWindows(SYSTEM_DIALOG_REASON_SCREENSHOT);

            PendingIntent actionIntent = intent.getParcelableExtra(EXTRA_ACTION_INTENT);
            ActivityOptions opts = ActivityOptions.makeBasic();
+0 −9
Original line number Diff line number Diff line
@@ -24,14 +24,12 @@ import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASO
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.app.PendingIntent;
import android.content.Context;
@@ -54,8 +52,6 @@ import org.mockito.stubbing.Answer;

import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

@RunWith(AndroidTestingRunner.class)
@@ -67,8 +63,6 @@ public class ActionProxyReceiverTest extends SysuiTestCase {
    @Mock
    private ActivityManagerWrapper mMockActivityManagerWrapper;
    @Mock
    private Future mMockFuture;
    @Mock
    private ScreenshotSmartActions mMockScreenshotSmartActions;
    @Mock
    private PendingIntent mMockPendingIntent;
@@ -80,9 +74,6 @@ public class ActionProxyReceiverTest extends SysuiTestCase {
        MockitoAnnotations.initMocks(this);
        mIntent = new Intent(mContext, ActionProxyReceiver.class)
                .putExtra(ScreenshotController.EXTRA_ACTION_INTENT, mMockPendingIntent);

        when(mMockActivityManagerWrapper.closeSystemWindows(anyString())).thenReturn(mMockFuture);
        when(mMockFuture.get(anyLong(), any(TimeUnit.class))).thenReturn(null);
    }

    @Test