Adding API to access / change the task bounds
Bug: 21738328
Change-Id: I3aabcbe1dcc5caa70f66554157f41fbfacf4c50f
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 84892a3..07fa52c 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -31,7 +31,7 @@
import android.transition.TransitionManager;
import android.util.ArrayMap;
import android.util.SuperNotCalledException;
-import android.view.Window.WindowStackCallback;
+import android.view.Window.WindowControllerCallback;
import android.widget.Toolbar;
import com.android.internal.app.IVoiceInteractor;
@@ -60,6 +60,7 @@
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
+import android.graphics.Rect;
import android.media.AudioManager;
import android.media.session.MediaController;
import android.net.Uri;
@@ -673,7 +674,7 @@
implements LayoutInflater.Factory2,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks2,
- Window.OnWindowDismissedCallback, WindowStackCallback {
+ Window.OnWindowDismissedCallback, WindowControllerCallback {
private static final String TAG = "Activity";
private static final boolean DEBUG_LIFECYCLE = false;
@@ -2712,7 +2713,8 @@
}
- /** Called to move the window and its activity/task to a different stack container.
+ /**
+ * Called to move the window and its activity/task to a different stack container.
* For example, a window can move between
* {@link android.app.ActivityManager#FULLSCREEN_WORKSPACE_STACK_ID} stack and
* {@link android.app.ActivityManager#FREEFORM_WORKSPACE_STACK_ID} stack.
@@ -2734,6 +2736,31 @@
}
/**
+ * Returns the bounds of the task that contains this activity.
+ *
+ * @return Rect The bounds that contains the activity.
+ * @hide
+ */
+ @Override
+ public Rect getActivityBounds() throws RemoteException {
+ return ActivityManagerNative.getDefault().getActivityBounds(mToken);
+ }
+
+ /**
+ * Sets the bounds (size and position) of the task or stack that contains this
+ * activity.
+ * NOTE: The requested bounds might not the fully honored by the system depending
+ * on the window placement policy.
+ *
+ * @param newBounds The new target bounds of the activity in task or stack.
+ * @hide
+ */
+ @Override
+ public void setActivityBounds(Rect newBounds) throws RemoteException {
+ ActivityManagerNative.getDefault().setActivityBounds(mToken, newBounds);
+ }
+
+ /**
* Called to process key events. You can override this to intercept all
* key events before they are dispatched to the window. Be sure to call
* this implementation for key events that should be handled normally.
@@ -6211,7 +6238,7 @@
mFragments.attachHost(null /*parent*/);
mWindow = new PhoneWindow(this);
- mWindow.setWindowStackCallback(this);
+ mWindow.setWindowControllerCallback(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 10c122a..5f33344 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -752,6 +752,24 @@
return true;
}
+ case GET_ACTIVITY_BOUNDS_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ IBinder token = data.readStrongBinder();
+ Rect r = getActivityBounds(token);
+ reply.writeNoException();
+ r.writeToParcel(reply, 0);
+ return true;
+ }
+
+ case SET_ACTIVITY_BOUNDS_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ IBinder token = data.readStrongBinder();
+ Rect r = Rect.CREATOR.createFromParcel(data);
+ setActivityBounds(token, r);
+ reply.writeNoException();
+ return true;
+ }
+
case POSITION_TASK_IN_STACK_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
int taskId = data.readInt();
@@ -5903,6 +5921,35 @@
}
@Override
+ public void setActivityBounds(IBinder token, Rect r) throws RemoteException
+ {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(token);
+ r.writeToParcel(data, 0);
+ mRemote.transact(SET_ACTIVITY_BOUNDS_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
+ @Override
+ public Rect getActivityBounds(IBinder token) throws RemoteException
+ {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(token);
+ mRemote.transact(GET_ACTIVITY_BOUNDS_TRANSACTION, data, reply, 0);
+ reply.readException();
+ Rect rect = Rect.CREATOR.createFromParcel(reply);
+ data.recycle();
+ reply.recycle();
+ return rect;
+ }
+
+ @Override
public Bitmap getTaskDescriptionIcon(String filename) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index ff1d595..d355219 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -490,6 +490,9 @@
throws RemoteException;
public void setTaskResizeable(int taskId, boolean resizeable) throws RemoteException;
public void resizeTask(int taskId, Rect bounds) throws RemoteException;
+ public void setActivityBounds(IBinder token, Rect bounds) throws RemoteException;
+ public Rect getActivityBounds(IBinder token) throws RemoteException;
+
public Rect getTaskBounds(int taskId) throws RemoteException;
public Bitmap getTaskDescriptionIcon(String filename) throws RemoteException;
@@ -887,4 +890,6 @@
int GET_ACTIVITY_STACK_ID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 343;
int MOVE_ACTIVITY_TO_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 344;
int REPORT_SIZE_CONFIGURATIONS = IBinder.FIRST_CALL_TRANSACTION + 345;
+ int GET_ACTIVITY_BOUNDS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 346;
+ int SET_ACTIVITY_BOUNDS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 347;
}
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index eecda89..1a9fb34 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -28,8 +28,9 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
-import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
import android.media.session.MediaController;
import android.net.Uri;
import android.os.Bundle;
@@ -183,7 +184,7 @@
private TypedArray mWindowStyle;
private Callback mCallback;
private OnWindowDismissedCallback mOnWindowDismissedCallback;
- private WindowStackCallback mWindowStackCallback;
+ private WindowControllerCallback mWindowControllerCallback;
private WindowManager mWindowManager;
private IBinder mAppToken;
private String mAppName;
@@ -479,8 +480,9 @@
}
/** @hide */
- public interface WindowStackCallback {
- /** Called to move the window and its activity/task to a different stack container.
+ public interface WindowControllerCallback {
+ /**
+ * Called to move the window and its activity/task to a different stack container.
* For example, a window can move between
* {@link android.app.ActivityManager#FULLSCREEN_WORKSPACE_STACK_ID} stack and
* {@link android.app.ActivityManager#FREEFORM_WORKSPACE_STACK_ID} stack.
@@ -491,6 +493,23 @@
/** Returns the current stack Id for the window. */
int getWindowStackId() throws RemoteException;
+
+ /**
+ * Returns the bounds of the task that contains this activity.
+ *
+ * @return Rect The bounds that contains the activity.
+ */
+ Rect getActivityBounds() throws RemoteException;
+
+ /**
+ * Sets the bounds (size and position) of the task or stack that contains this
+ * activity.
+ * NOTE: The requested bounds might not the fully honored by the system depending
+ * on the window placement policy.
+ *
+ * @param newBounds The new target bounds of the activity in task or stack.
+ */
+ void setActivityBounds(Rect newBounds) throws RemoteException;
}
public Window(Context context) {
@@ -682,13 +701,13 @@
}
/** @hide */
- public final void setWindowStackCallback(WindowStackCallback wscb) {
- mWindowStackCallback = wscb;
+ public final void setWindowControllerCallback(WindowControllerCallback wccb) {
+ mWindowControllerCallback = wccb;
}
/** @hide */
- public final WindowStackCallback getWindowStackCallback() {
- return mWindowStackCallback;
+ public final WindowControllerCallback getWindowControllerCallback() {
+ return mWindowControllerCallback;
}
/**
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 1068b51..57891a1 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -5187,7 +5187,7 @@
**/
private int getWorkspaceId() {
int workspaceId = FULLSCREEN_WORKSPACE_STACK_ID;
- WindowStackCallback callback = getWindowStackCallback();
+ WindowControllerCallback callback = getWindowControllerCallback();
if (callback != null) {
try {
workspaceId = callback.getWindowStackId();
diff --git a/core/java/com/android/internal/widget/NonClientDecorView.java b/core/java/com/android/internal/widget/NonClientDecorView.java
index d8626cd..dd5c5d7 100644
--- a/core/java/com/android/internal/widget/NonClientDecorView.java
+++ b/core/java/com/android/internal/widget/NonClientDecorView.java
@@ -17,6 +17,7 @@
package com.android.internal.widget;
import android.content.Context;
+import android.graphics.Rect;
import android.os.RemoteException;
import android.util.AttributeSet;
import android.view.View;
@@ -243,7 +244,7 @@
* Maximize the window by moving it to the maximized workspace stack.
**/
private void maximizeWindow() {
- Window.WindowStackCallback callback = mOwner.getWindowStackCallback();
+ Window.WindowControllerCallback callback = mOwner.getWindowControllerCallback();
if (callback != null) {
try {
callback.changeWindowStack(
@@ -253,4 +254,40 @@
}
}
}
+
+ /**
+ * Returns the bounds of this activity.
+ * @return Returns bounds of the activity. It will return null if either the window is
+ * fullscreen or the bounds could not be retrieved.
+ */
+ private Rect getActivityBounds() {
+ Window.WindowControllerCallback callback = mOwner.getWindowControllerCallback();
+ if (callback != null) {
+ try {
+ return callback.getActivityBounds();
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Failed to get the activity bounds.");
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Sets the bounds of this Activity on the stack.
+ * @param newBounds The bounds of the activity. Passing null is not allowed.
+ */
+ private void setActivityBounds(Rect newBounds) {
+ if (newBounds == null) {
+ Log.e(TAG, "Failed to set null bounds to the activity.");
+ return;
+ }
+ Window.WindowControllerCallback callback = mOwner.getWindowControllerCallback();
+ if (callback != null) {
+ try {
+ callback.setActivityBounds(newBounds);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Failed to set the activity bounds.");
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2be3bf7..19ad930 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -8639,6 +8639,54 @@
}
@Override
+ public void setActivityBounds(IBinder token, Rect bounds) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (this) {
+ final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+ if (r == null) {
+ Slog.w(TAG, "setActivityBounds: token=" + token + " not found");
+ return;
+ }
+ final TaskRecord task = r.task;
+ if (task == null) {
+ Slog.e(TAG, "setActivityBounds: No TaskRecord for the ActivityRecord r=" + r);
+ return;
+ }
+ mStackSupervisor.resizeTaskLocked(task, bounds);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public Rect getActivityBounds(IBinder token) {
+ long ident = Binder.clearCallingIdentity();
+ Rect rect = null;
+ try {
+ synchronized (this) {
+ final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+ if (r == null) {
+ Slog.w(TAG, "getActivityBounds: token=" + token + " not found");
+ return rect;
+ }
+ final TaskRecord task = r.task;
+ if (task == null) {
+ Slog.e(TAG, "getActivityBounds: No TaskRecord for the ActivityRecord r=" + r);
+ return rect;
+ }
+ if (task.mBounds != null) {
+ rect = new Rect(task.mBounds);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ return rect;
+ }
+
+ @Override
public Bitmap getTaskDescriptionIcon(String filename) {
if (!FileUtils.isValidExtFilename(filename)
|| !filename.contains(ActivityRecord.ACTIVITY_ICON_SUFFIX)) {