Merge "Add transparent frame around focused stack."
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 4f0000e..f3be0ea 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -218,6 +218,7 @@
static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false;
static final boolean DEBUG_MU = localLOGV || false;
static final boolean DEBUG_IMMERSIVE = localLOGV || false;
+ static final boolean DEBUG_STACK = localLOGV || false;
static final boolean VALIDATE_TOKENS = true;
static final boolean SHOW_ACTIVITY_START_TIME = true;
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 5aa056c..0711f74 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -82,6 +82,7 @@
static final boolean DEBUG_CONFIGURATION = ActivityManagerService.DEBUG_CONFIGURATION;
static final boolean DEBUG_TASKS = ActivityManagerService.DEBUG_TASKS;
static final boolean DEBUG_CLEANUP = ActivityManagerService.DEBUG_CLEANUP;
+ static final boolean DEBUG_STACK = ActivityManagerService.DEBUG_STACK;
static final boolean DEBUG_STATES = ActivityStackSupervisor.DEBUG_STATES;
static final boolean DEBUG_ADD_REMOVE = ActivityStackSupervisor.DEBUG_ADD_REMOVE;
@@ -2836,6 +2837,8 @@
}
final TaskRecord task = r.task;
if (task != null && task.removeActivity(r)) {
+ if (DEBUG_STACK) Slog.i(TAG,
+ "removeActivityFromHistoryLocked: last activity removed from " + this);
mStackSupervisor.removeTask(task);
}
r.takeFromHistory();
diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java
index 8b946e4..7a6687e 100644
--- a/services/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/java/com/android/server/am/ActivityStackSupervisor.java
@@ -72,6 +72,8 @@
import java.util.List;
public class ActivityStackSupervisor {
+ static final boolean DEBUG_STACK = ActivityManagerService.DEBUG_STACK;
+
static final boolean DEBUG = ActivityManagerService.DEBUG || false;
static final boolean DEBUG_ADD_REMOVE = DEBUG || false;
static final boolean DEBUG_APP = DEBUG || false;
@@ -237,9 +239,11 @@
void removeTask(TaskRecord task) {
final ActivityStack stack = task.stack;
if (stack.removeTask(task) && !stack.isHomeStack()) {
+ if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing stack " + stack);
mStacks.remove(stack);
final int stackId = stack.mStackId;
final int nextStackId = mService.mWindowManager.removeStack(stackId);
+ // TODO: Perhaps we need to let the ActivityManager determine the next focus...
if (mFocusedStack.mStackId == stackId) {
mFocusedStack = nextStackId == HOME_STACK_ID ? null : getStack(nextStackId);
}
diff --git a/services/java/com/android/server/wm/FocusedStackFrame.java b/services/java/com/android/server/wm/FocusedStackFrame.java
new file mode 100644
index 0000000..29949ad
--- /dev/null
+++ b/services/java/com/android/server/wm/FocusedStackFrame.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2013 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.server.wm;
+
+import static com.android.server.wm.WindowManagerService.DEBUG_STACK;
+
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.util.Slog;
+import android.view.Display;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.view.SurfaceSession;
+
+class FocusedStackFrame {
+ private static final String TAG = "FocusedStackFrame";
+ private static final int THICKNESS = 10;
+ private static final float ALPHA = 0.3f;
+
+ private final SurfaceControl mSurfaceControl;
+ private final Surface mSurface = new Surface();
+ private Rect mLastBounds = new Rect();
+ private Rect mBounds = new Rect();
+ private Rect mTmpDrawRect = new Rect();
+
+ public FocusedStackFrame(Display display, SurfaceSession session) {
+ SurfaceControl ctrl = null;
+ try {
+ ctrl = new SurfaceControl(session, "FocusedStackFrame",
+ 1, 1, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
+ ctrl.setLayerStack(display.getLayerStack());
+ ctrl.setLayer(WindowManagerService.TYPE_LAYER_MULTIPLIER * 102);
+ ctrl.setAlpha(ALPHA);
+ mSurface.copyFrom(ctrl);
+ } catch (SurfaceControl.OutOfResourcesException e) {
+ }
+ mSurfaceControl = ctrl;
+ }
+
+ private void draw(Rect bounds, int color) {
+ if (DEBUG_STACK) Slog.i(TAG, "draw: bounds=" + bounds.toShortString() +
+ " color=" + Integer.toHexString(color));
+ mTmpDrawRect.set(bounds);
+ Canvas c = null;
+ try {
+ c = mSurface.lockCanvas(mTmpDrawRect);
+ } catch (IllegalArgumentException e) {
+ } catch (Surface.OutOfResourcesException e) {
+ }
+ if (c == null) {
+ return;
+ }
+
+ final int w = bounds.width();
+ final int h = bounds.height();
+
+ // Top
+ mTmpDrawRect.set(0, 0, w, THICKNESS);
+ c.clipRect(mTmpDrawRect, Region.Op.REPLACE);
+ c.drawColor(color);
+ // Left (not including Top or Bottom stripe).
+ mTmpDrawRect.set(0, THICKNESS, THICKNESS, h - THICKNESS);
+ c.clipRect(mTmpDrawRect, Region.Op.REPLACE);
+ c.drawColor(color);
+ // Right (not including Top or Bottom stripe).
+ mTmpDrawRect.set(w - THICKNESS, THICKNESS, w, h - THICKNESS);
+ c.clipRect(mTmpDrawRect, Region.Op.REPLACE);
+ c.drawColor(color);
+ // Bottom
+ mTmpDrawRect.set(0, h - THICKNESS, w, h);
+ c.clipRect(mTmpDrawRect, Region.Op.REPLACE);
+ c.drawColor(color);
+
+ mSurface.unlockCanvasAndPost(c);
+ }
+
+ private void positionSurface(Rect bounds) {
+ if (DEBUG_STACK) Slog.i(TAG, "positionSurface: bounds=" + bounds.toShortString());
+ mSurfaceControl.setSize(bounds.width(), bounds.height());
+ mSurfaceControl.setPosition(bounds.left, bounds.top);
+ }
+
+ // Note: caller responsible for being inside
+ // Surface.openTransaction() / closeTransaction()
+ public void setVisibility(boolean on) {
+ if (DEBUG_STACK) Slog.i(TAG, "setVisibility: on=" + on +
+ " mLastBounds=" + mLastBounds.toShortString() +
+ " mBounds=" + mBounds.toShortString());
+ if (mSurfaceControl == null) {
+ return;
+ }
+ if (on) {
+ if (!mLastBounds.equals(mBounds)) {
+ // Erase the previous rectangle.
+ positionSurface(mLastBounds);
+ draw(mLastBounds, Color.TRANSPARENT);
+ // Draw the latest rectangle.
+ positionSurface(mBounds);
+ draw(mBounds, Color.WHITE);
+ // Update the history.
+ mLastBounds.set(mBounds);
+ }
+ mSurfaceControl.show();
+ } else {
+ mSurfaceControl.hide();
+ }
+ }
+
+ public void setBounds(Rect bounds) {
+ if (DEBUG_STACK) Slog.i(TAG, "setBounds: bounds=" + bounds);
+ mBounds.set(bounds);
+ }
+}
diff --git a/services/java/com/android/server/wm/StackBox.java b/services/java/com/android/server/wm/StackBox.java
index b195f0b..83f32e9 100644
--- a/services/java/com/android/server/wm/StackBox.java
+++ b/services/java/com/android/server/wm/StackBox.java
@@ -17,8 +17,11 @@
package com.android.server.wm;
import android.graphics.Rect;
+import android.util.Slog;
import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
+import static com.android.server.wm.WindowManagerService.DEBUG_STACK;
+import static com.android.server.wm.WindowManagerService.TAG;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -230,24 +233,28 @@
* @return The first stackId of the resulting StackBox. */
int remove() {
if (mStack != null) {
+ if (DEBUG_STACK) Slog.i(TAG, "StackBox.remove: removing stackId=" + mStack.mStackId);
mDisplayContent.mStackHistory.remove(mStack);
}
mDisplayContent.layoutNeeded = true;
if (mParent == null) {
// This is the top-plane stack.
+ if (DEBUG_STACK) Slog.i(TAG, "StackBox.remove: removing top plane.");
mDisplayContent.removeStackBox(this);
return HOME_STACK_ID;
}
StackBox sibling = isFirstChild() ? mParent.mSecond : mParent.mFirst;
StackBox grandparent = mParent.mParent;
+ sibling.mParent = grandparent;
if (grandparent == null) {
// mParent is a top-plane stack. Now sibling will be.
+ if (DEBUG_STACK) Slog.i(TAG, "StackBox.remove: grandparent null");
mDisplayContent.removeStackBox(mParent);
mDisplayContent.addStackBox(sibling, true);
} else {
- sibling.mParent = grandparent;
+ if (DEBUG_STACK) Slog.i(TAG, "StackBox.remove: grandparent getting sibling");
if (mParent.isFirstChild()) {
grandparent.mFirst = sibling;
} else {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index a5df7d9..d21b111 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -401,6 +401,7 @@
final SurfaceSession mFxSession;
Watermark mWatermark;
StrictModeFlash mStrictModeFlash;
+ FocusedStackFrame mFocusedStackFrame;
final float[] mTmpFloats = new float[9];
@@ -793,6 +794,8 @@
SurfaceControl.openTransaction();
try {
createWatermarkInTransaction();
+ mFocusedStackFrame = new FocusedStackFrame(
+ getDefaultDisplayContentLocked().getDisplay(), mFxSession);
} finally {
SurfaceControl.closeTransaction();
}
@@ -3682,6 +3685,25 @@
}
}
+ void setFocusedStackFrame(TaskStack stack) {
+ if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setFocusedStackFrame");
+ SurfaceControl.openTransaction();
+ try {
+ if (stack == null) {
+ mFocusedStackFrame.setVisibility(false);
+ } else {
+ final StackBox box = stack.mStackBox;
+ final Rect bounds = box.mBounds;
+ final boolean multipleStacks = box.mParent != null;
+ mFocusedStackFrame.setBounds(bounds);
+ mFocusedStackFrame.setVisibility(multipleStacks);
+ }
+ } finally {
+ SurfaceControl.closeTransaction();
+ if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> CLOSE TRANSACTION setFocusedStackFrame");
+ }
+ }
+
@Override
public void setFocusedApp(IBinder token, boolean moveFocusNow) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
@@ -4746,13 +4768,16 @@
}
public int removeStack(int stackId) {
- final TaskStack stack = mStackIdToStack.get(stackId);
- if (stack != null) {
- mStackIdToStack.delete(stackId);
- int nextStackId = stack.remove();
- stack.getDisplayContent().layoutNeeded = true;
- performLayoutAndPlaceSurfacesLocked();
- return nextStackId;
+ synchronized (mWindowMap) {
+ final TaskStack stack = mStackIdToStack.get(stackId);
+ if (stack != null) {
+ mStackIdToStack.delete(stackId);
+ int nextStackId = stack.remove();
+ stack.getDisplayContent().layoutNeeded = true;
+ performLayoutAndPlaceSurfacesLocked();
+ return nextStackId;
+ }
+ if (DEBUG_STACK) Slog.i(TAG, "removeStack: could not find stackId=" + stackId);
}
return HOME_STACK_ID;
}
@@ -9236,6 +9261,10 @@
}
}
+ final TaskStack stack = mFocusedApp != null ?
+ mTaskIdToTask.get(mFocusedApp.groupId).mStack : null;
+ setFocusedStackFrame(stack);
+
// Check to see if we are now in a state where the screen should
// be enabled, because the window obscured flags have changed.
enableScreenIfNeededLocked();