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

Commit b9bba581 authored by Hall Liu's avatar Hall Liu
Browse files

Expose the HomeVisibilityListener API

Rename HomeVisibilityObserver to HomeVisibilityListener and expose it as
module-only API. This listener is used by the SIM toolkit to detect when
the home screen is visible.

Also fix some bugs in the original implementation that were uncovered
during CTS writing.

Fixes: 170226810
Test: atest ActivityManagerTest#testHomeVisibilityListener
Change-Id: I5d99f2bad144711d7135cc800921abf01df6235d
parent 16b02d48
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
// Signature format: 2.0
package android.app {

  public class ActivityManager {
    method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void addHomeVisibilityListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.HomeVisibilityListener);
    method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void removeHomeVisibilityListener(@NonNull android.app.HomeVisibilityListener);
  }

  public class AppOpsManager {
    field public static final String OPSTR_NO_ISOLATED_STORAGE = "android:no_isolated_storage";
  }

  public abstract class HomeVisibilityListener {
    ctor public HomeVisibilityListener();
    method public abstract void onHomeVisibilityChanged(boolean);
  }

  public class NotificationManager {
    method public boolean hasEnabledNotificationListener(@NonNull String, @NonNull android.os.UserHandle);
    field public static final String ACTION_NOTIFICATION_LISTENER_ENABLED_CHANGED = "android.app.action.NOTIFICATION_LISTENER_ENABLED_CHANGED";
+7 −0
Original line number Diff line number Diff line
@@ -77,6 +77,7 @@ package android.app {
  }

  public class ActivityManager {
    method @RequiresPermission("android.permission.SET_ACTIVITY_WATCHER") public void addHomeVisibilityListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.HomeVisibilityListener);
    method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int);
    method public void alwaysShowUnsupportedCompileSdkWarning(android.content.ComponentName);
    method @RequiresPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) public void forceStopPackage(String);
@@ -86,6 +87,7 @@ package android.app {
    method @RequiresPermission("android.permission.INJECT_EVENTS") public void holdLock(int);
    method public static boolean isHighEndGfx();
    method @RequiresPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) public void killProcessesWhenImperceptible(@NonNull int[], @NonNull String);
    method @RequiresPermission("android.permission.SET_ACTIVITY_WATCHER") public void removeHomeVisibilityListener(@NonNull android.app.HomeVisibilityListener);
    method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener);
    method @RequiresPermission(android.Manifest.permission.RESET_APP_ERRORS) public void resetAppErrors();
    method public static void resumeAppSwitches() throws android.os.RemoteException;
@@ -456,6 +458,11 @@ package android.app {
    method @RequiresPermission("android.permission.WRITE_DREAM_STATE") public void stopDream();
  }

  public abstract class HomeVisibilityListener {
    ctor public HomeVisibilityListener();
    method public abstract void onHomeVisibilityChanged(boolean);
  }

  public final class NotificationChannel implements android.os.Parcelable {
    method public int getOriginalImportance();
    method public boolean isBlockable();
+25 −12
Original line number Diff line number Diff line
@@ -100,6 +100,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.Executor;

/**
 * <p>
@@ -4752,31 +4753,43 @@ public class ActivityManager {
    }

    /**
     * Register with {@link HomeVisibilityObserver} with ActivityManager.
     * TODO: b/144351078 expose as SystemApi
     * Register to be notified when the visibility of the home screen changes.
     *
     * @param executor The executor on which the listener should be called.
     * @param listener The listener that is called when home visibility changes.
     * @hide
     */
    public void registerHomeVisibilityObserver(@NonNull HomeVisibilityObserver observer) {
        Preconditions.checkNotNull(observer);
    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
    @TestApi
    @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
    public void addHomeVisibilityListener(@NonNull Executor executor,
            @NonNull HomeVisibilityListener listener) {
        Preconditions.checkNotNull(listener);
        Preconditions.checkNotNull(executor);
        try {
            observer.init(mContext, this);
            getService().registerProcessObserver(observer.mObserver);
            listener.init(mContext, executor, this);
            getService().registerProcessObserver(listener.mObserver);
            // Notify upon first registration.
            observer.onHomeVisibilityChanged(observer.mIsHomeActivityVisible);
            executor.execute(() ->
                    listener.onHomeVisibilityChanged(listener.mIsHomeActivityVisible));
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Unregister with {@link HomeVisibilityObserver} with ActivityManager.
     * TODO: b/144351078 expose as SystemApi
     * Removes a listener that was previously added with {@link #addHomeVisibilityListener}.
     *
     * @param listener The listener that was previously added.
     * @hide
     */
    public void unregisterHomeVisibilityObserver(@NonNull HomeVisibilityObserver observer) {
        Preconditions.checkNotNull(observer);
    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
    @TestApi
    @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
    public void removeHomeVisibilityListener(@NonNull HomeVisibilityListener listener) {
        Preconditions.checkNotNull(listener);
        try {
            getService().unregisterProcessObserver(observer.mObserver);
            getService().unregisterProcessObserver(listener.mObserver);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
+39 −24
Original line number Diff line number Diff line
@@ -16,49 +16,56 @@

package android.app;

import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Binder;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;

/**
 * An observer / callback to create and register by
 * {@link ActivityManager#registerHomeVisibilityObserver} so that it's triggered when
 * visibility of home page changes.
 * TODO: b/144351078 expose as SystemApi
 * A listener that will be invoked when the visibility of the home screen changes.
 * Register this callback via {@link ActivityManager#addHomeVisibilityListener}
 * @hide
 */
public abstract class HomeVisibilityObserver {
// This is a single-method listener that needs a bunch of supporting code, so it can't be an
// interface
@SuppressLint("ListenerInterface")
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@TestApi
public abstract class HomeVisibilityListener {
    private Context mContext;
    private ActivityManager mActivityManager;
    private Executor mExecutor;
    /** @hide */
    IProcessObserver.Stub mObserver;
    android.app.IProcessObserver.Stub mObserver;
    /** @hide */
    boolean mIsHomeActivityVisible;

    /** @hide */
    void init(Context context, ActivityManager activityManager) {
    void init(Context context, Executor executor, ActivityManager activityManager) {
        mContext = context;
        mActivityManager = activityManager;
        mIsHomeActivityVisible = isHomeActivityVisible();
        mExecutor = executor;
    }

    /**
     * The API that needs implemented and will be triggered when activity on home page changes.
     * Called when the visibility of the home screen changes.
     *
     * @param isHomeActivityVisible Whether the home screen activity is now visible.
     */
    public abstract void onHomeVisibilityChanged(boolean isHomeActivityVisible);

    public HomeVisibilityObserver() {
        mObserver = new IProcessObserver.Stub() {
    public HomeVisibilityListener() {
        mObserver = new android.app.IProcessObserver.Stub() {
            @Override
            public void onForegroundActivitiesChanged(int pid, int uid, boolean fg) {
                boolean isHomeActivityVisible = isHomeActivityVisible();
                if (mIsHomeActivityVisible != isHomeActivityVisible) {
                    mIsHomeActivityVisible = isHomeActivityVisible;
                    onHomeVisibilityChanged(mIsHomeActivityVisible);
                }
                refreshHomeVisibility();
            }

            @Override
@@ -67,6 +74,17 @@ public abstract class HomeVisibilityObserver {

            @Override
            public void onProcessDied(int pid, int uid) {
                refreshHomeVisibility();
            }

            private void refreshHomeVisibility() {
                boolean isHomeActivityVisible = isHomeActivityVisible();
                if (mIsHomeActivityVisible != isHomeActivityVisible) {
                    mIsHomeActivityVisible = isHomeActivityVisible;
                    Binder.withCleanCallingIdentity(() ->
                            mExecutor.execute(() ->
                                    onHomeVisibilityChanged(mIsHomeActivityVisible)));
                }
            }
        };
    }
@@ -83,12 +101,9 @@ public abstract class HomeVisibilityObserver {
        }

        // We can assume that the screen is idle if the home application is in the foreground.
        final Intent intent = new Intent(Intent.ACTION_MAIN, null);
        intent.addCategory(Intent.CATEGORY_HOME);

        ResolveInfo info = mContext.getPackageManager().resolveActivity(intent,
                PackageManager.MATCH_DEFAULT_ONLY);
        if (info != null && top.equals(info.activityInfo.packageName)) {
        String defaultHomePackage = mContext.getPackageManager()
                .getHomeActivities(new ArrayList<>()).getPackageName();
        if (Objects.equals(top, defaultHomePackage)) {
            return true;
        }

+10 −0
Original line number Diff line number Diff line
// Signature format: 2.0
package android.app {

  public class ActivityManager {
    method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void addHomeVisibilityListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.HomeVisibilityListener);
    method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void removeHomeVisibilityListener(@NonNull android.app.HomeVisibilityListener);
  }

  public class AppOpsManager {
    field public static final String OPSTR_NO_ISOLATED_STORAGE = "android:no_isolated_storage";
  }

  public abstract class HomeVisibilityListener {
    ctor public HomeVisibilityListener();
    method public abstract void onHomeVisibilityChanged(boolean);
  }

  public class NotificationManager {
    method public boolean hasEnabledNotificationListener(@NonNull String, @NonNull android.os.UserHandle);
    field public static final String ACTION_NOTIFICATION_LISTENER_ENABLED_CHANGED = "android.app.action.NOTIFICATION_LISTENER_ENABLED_CHANGED";