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

Commit aec68bb8 authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Fix issue #17038762: Add API to add entries to the recents list

New API Added to ActivityManager for adding an entry.  See docs
there.

Repercussions:

- I hit a bug in system UI where if the thumbnail has alpha, it tries
  to modify it, but thumbnails are loading immutable so crashes.  Fixed
  this by loading the bitmaps to be mutable.
- Improved dump output of recents; there was a lot of stuff missing.
  Also split the recents dump output from the rest of the activity
  output, since it can be really large.
- Added tests to the lovely ActivityTest app.

Bonus: new method on AppTask to control the exclude from recents flag.

Change-Id: I01e543db4d15320ee1701e95872fef73c116526c
parent cf038760
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -3593,8 +3593,11 @@ package android.app {
  }
  public class ActivityManager {
    method public int addAppTask(android.app.Activity, android.content.Intent, android.app.ActivityManager.TaskDescription, android.graphics.Bitmap);
    method public boolean clearApplicationUserData();
    method public void dumpPackageState(java.io.FileDescriptor, java.lang.String);
    method public int getAppTaskThumbnailHeight();
    method public int getAppTaskThumbnailWidth();
    method public java.util.List<android.app.ActivityManager.AppTask> getAppTasks();
    method public android.content.pm.ConfigurationInfo getDeviceConfigurationInfo();
    method public int getLargeMemoryClass();
@@ -3628,6 +3631,7 @@ package android.app {
  public static class ActivityManager.AppTask {
    method public void finishAndRemoveTask();
    method public android.app.ActivityManager.RecentTaskInfo getTaskInfo();
    method public void setExcludeFromRecents(boolean);
  }
  public static class ActivityManager.MemoryInfo implements android.os.Parcelable {
+119 −3
Original line number Diff line number Diff line
@@ -16,6 +16,11 @@

package android.app;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Point;
import android.os.BatteryStats;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
@@ -47,16 +52,13 @@ import android.os.SystemProperties;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Slog;

import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Interact with the overall activities running in the system.
@@ -297,6 +299,8 @@ public class ActivityManager {
    /** @hide Process is being cached for later use and is empty. */
    public static final int PROCESS_STATE_CACHED_EMPTY = 13;

    Point mAppTaskThumbnailSize;

    /*package*/ ActivityManager(Context context, Handler handler) {
        mContext = context;
        mHandler = handler;
@@ -993,6 +997,103 @@ public class ActivityManager {
        return tasks;
    }

    /**
     * Return the current design width for {@link AppTask} thumbnails, for use
     * with {@link #addAppTask}.
     */
    public int getAppTaskThumbnailWidth() {
        synchronized (this) {
            ensureAppTaskThumbnailSizeLocked();
            return mAppTaskThumbnailSize.x;
        }
    }

    /**
     * Return the current design height for {@link AppTask} thumbnails, for use
     * with {@link #addAppTask}.
     */
    public int getAppTaskThumbnailHeight() {
        synchronized (this) {
            ensureAppTaskThumbnailSizeLocked();
            return mAppTaskThumbnailSize.y;
        }
    }

    private void ensureAppTaskThumbnailSizeLocked() {
        if (mAppTaskThumbnailSize == null) {
            try {
                mAppTaskThumbnailSize = ActivityManagerNative.getDefault().getAppTaskThumbnailSize();
            } catch (RemoteException e) {
                throw new IllegalStateException("System dead?", e);
            }
        }
    }

    /**
     * Add a new {@link AppTask} for the calling application.  This will create a new
     * recents entry that is added to the <b>end</b> of all existing recents.
     *
     * @param activity The activity that is adding the entry.   This is used to help determine
     * the context that the new recents entry will be in.
     * @param intent The Intent that describes the recents entry.  This is the same Intent that
     * you would have used to launch the activity for it.  In generally you will want to set
     * both {@link Intent#FLAG_ACTIVITY_NEW_DOCUMENT} and
     * {@link Intent#FLAG_ACTIVITY_RETAIN_IN_RECENTS}; the latter is required since this recents
     * entry will exist without an activity, so it doesn't make sense to not retain it when
     * its activity disappears.  The given Intent here also must have an explicit ComponentName
     * set on it.
     * @param description Optional additional description information.
     * @param thumbnail Thumbnail to use for the recents entry.  Should be the size given by
     * {@link #getAppTaskThumbnailWidth()} and {@link #getAppTaskThumbnailHeight()}.  If the
     * bitmap is not that exact size, it will be recreated in your process, probably in a way
     * you don't like, before the recents entry is added.
     *
     * @return Returns the task id of the newly added app task, or -1 if the add failed.  The
     * most likely cause of failure is that there is no more room for more tasks for your app.
     */
    public int addAppTask(@NonNull Activity activity, @NonNull Intent intent,
            @Nullable TaskDescription description, @NonNull Bitmap thumbnail) {
        Point size;
        synchronized (this) {
            ensureAppTaskThumbnailSizeLocked();
            size = mAppTaskThumbnailSize;
        }
        final int tw = thumbnail.getWidth();
        final int th = thumbnail.getHeight();
        if (tw != size.x || th != size.y) {
            Bitmap bm = Bitmap.createBitmap(size.x, size.y, thumbnail.getConfig());

            // Use ScaleType.CENTER_CROP, except we leave the top edge at the top.
            float scale;
            float dx = 0, dy = 0;
            if (tw * size.x > size.y * th) {
                scale = (float) size.x / (float) th;
                dx = (size.y - tw * scale) * 0.5f;
            } else {
                scale = (float) size.y / (float) tw;
                dy = (size.x - th * scale) * 0.5f;
            }
            Matrix matrix = new Matrix();
            matrix.setScale(scale, scale);
            matrix.postTranslate((int) (dx + 0.5f), 0);

            Canvas canvas = new Canvas(bm);
            canvas.drawBitmap(thumbnail, matrix, null);
            canvas.setBitmap(null);

            thumbnail = bm;
        }
        if (description == null) {
            description = new TaskDescription();
        }
        try {
            return ActivityManagerNative.getDefault().addAppTask(activity.getActivityToken(),
                    intent, description, thumbnail);
        } catch (RemoteException e) {
            throw new IllegalStateException("System dead?", e);
        }
    }

    /**
     * Return a list of the tasks that are currently running, with
     * the most recent being first and older ones after in order.  Note that
@@ -2514,5 +2615,20 @@ public class ActivityManager {
                return null;
            }
        }

        /**
         * Modify the {@link Intent#FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS} flag in the root
         * Intent of this AppTask.
         *
         * @param exclude If true, {@link Intent#FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS} will
         * be set; otherwise, it will be cleared.
         */
        public void setExcludeFromRecents(boolean exclude) {
            try {
                mAppTaskImpl.setExcludeFromRecents(exclude);
            } catch (RemoteException e) {
                Slog.e(TAG, "Invalid AppTask", e);
            }
        }
    }
}
+50 −0
Original line number Diff line number Diff line
@@ -30,6 +30,8 @@ import android.content.pm.IPackageDataObserver;
import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Binder;
@@ -564,6 +566,27 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
            return true;
        }

        case ADD_APP_TASK_TRANSACTION: {
            data.enforceInterface(IActivityManager.descriptor);
            IBinder activityToken = data.readStrongBinder();
            Intent intent = Intent.CREATOR.createFromParcel(data);
            ActivityManager.TaskDescription descr
                    = ActivityManager.TaskDescription.CREATOR.createFromParcel(data);
            Bitmap thumbnail = Bitmap.CREATOR.createFromParcel(data);
            int res = addAppTask(activityToken, intent, descr, thumbnail);
            reply.writeNoException();
            reply.writeInt(res);
            return true;
        }

        case GET_APP_TASK_THUMBNAIL_SIZE_TRANSACTION: {
            data.enforceInterface(IActivityManager.descriptor);
            Point size = getAppTaskThumbnailSize();
            reply.writeNoException();
            size.writeToParcel(reply, 0);
            return true;
        }

        case GET_TASKS_TRANSACTION: {
            data.enforceInterface(IActivityManager.descriptor);
            int maxNum = data.readInt();
@@ -2877,6 +2900,33 @@ class ActivityManagerProxy implements IActivityManager
        reply.recycle();
        return list;
    }
    public int addAppTask(IBinder activityToken, Intent intent,
            ActivityManager.TaskDescription description, Bitmap thumbnail) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(activityToken);
        intent.writeToParcel(data, 0);
        description.writeToParcel(data, 0);
        thumbnail.writeToParcel(data, 0);
        mRemote.transact(ADD_APP_TASK_TRANSACTION, data, reply, 0);
        reply.readException();
        int res = reply.readInt();
        data.recycle();
        reply.recycle();
        return res;
    }
    public Point getAppTaskThumbnailSize() throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        mRemote.transact(GET_APP_TASK_THUMBNAIL_SIZE_TRANSACTION, data, reply, 0);
        reply.readException();
        Point size = Point.CREATOR.createFromParcel(reply);
        data.recycle();
        reply.recycle();
        return size;
    }
    public List getTasks(int maxNum, int flags) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
+6 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import android.content.pm.ProviderInfo;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Bundle;
@@ -119,6 +120,9 @@ public interface IActivityManager extends IInterface {
    public String getCallingPackage(IBinder token) throws RemoteException;
    public ComponentName getCallingActivity(IBinder token) throws RemoteException;
    public List<IAppTask> getAppTasks() throws RemoteException;
    public int addAppTask(IBinder activityToken, Intent intent,
            ActivityManager.TaskDescription description, Bitmap thumbnail) throws RemoteException;
    public Point getAppTaskThumbnailSize() throws RemoteException;
    public List<RunningTaskInfo> getTasks(int maxNum, int flags) throws RemoteException;
    public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
            int flags, int userId) throws RemoteException;
@@ -765,4 +769,6 @@ public interface IActivityManager extends IInterface {
    int NOTIFY_ENTER_ANIMATION_COMPLETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+230;
    int KEYGUARD_WAITING_FOR_ACTIVITY_DRAWN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+231;
    int START_ACTIVITY_AS_CALLER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+232;
    int ADD_APP_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+233;
    int GET_APP_TASK_THUMBNAIL_SIZE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+234;
}
+1 −0
Original line number Diff line number Diff line
@@ -22,4 +22,5 @@ import android.app.ActivityManager;
interface IAppTask {
    void finishAndRemoveTask();
    ActivityManager.RecentTaskInfo getTaskInfo();
    void setExcludeFromRecents(boolean exclude);
}
Loading