diff options
19 files changed, 400 insertions, 242 deletions
diff --git a/core/java/android/net/http/X509TrustManagerExtensions.java b/core/java/android/net/http/X509TrustManagerExtensions.java index 25ef8b500cda..67293475a9e7 100644 --- a/core/java/android/net/http/X509TrustManagerExtensions.java +++ b/core/java/android/net/http/X509TrustManagerExtensions.java @@ -20,6 +20,9 @@ import android.annotation.SystemApi; import com.android.org.conscrypt.TrustManagerImpl; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.List; @@ -36,7 +39,11 @@ import javax.net.ssl.X509TrustManager; */ public class X509TrustManagerExtensions { - final TrustManagerImpl mDelegate; + private final TrustManagerImpl mDelegate; + // Methods to use when mDelegate is not a TrustManagerImpl and duck typing is being used. + private final X509TrustManager mTrustManager; + private final Method mCheckServerTrusted; + private final Method mIsUserAddedCertificate; /** * Constructs a new X509TrustManagerExtensions wrapper. @@ -47,10 +54,31 @@ public class X509TrustManagerExtensions { public X509TrustManagerExtensions(X509TrustManager tm) throws IllegalArgumentException { if (tm instanceof TrustManagerImpl) { mDelegate = (TrustManagerImpl) tm; - } else { - mDelegate = null; - throw new IllegalArgumentException("tm is an instance of " + tm.getClass().getName() + - " which is not a supported type of X509TrustManager"); + mTrustManager = null; + mCheckServerTrusted = null; + mIsUserAddedCertificate = null; + return; + } + // Use duck typing if possible. + mDelegate = null; + mTrustManager = tm; + // Check that the hostname aware checkServerTrusted is present. + try { + mCheckServerTrusted = tm.getClass().getMethod("checkServerTrusted", + X509Certificate[].class, + String.class, + String.class); + } catch (NoSuchMethodException e) { + throw new IllegalArgumentException("Required method" + + " checkServerTrusted(X509Certificate[], String, String, String) missing"); + } + // Check that isUserAddedCertificate is present. + try { + mIsUserAddedCertificate = tm.getClass().getMethod("isUserAddedCertificate", + X509Certificate.class); + } catch (NoSuchMethodException e) { + throw new IllegalArgumentException( + "Required method isUserAddedCertificate(X509Certificate) missing"); } } @@ -66,7 +94,24 @@ public class X509TrustManagerExtensions { */ public List<X509Certificate> checkServerTrusted(X509Certificate[] chain, String authType, String host) throws CertificateException { - return mDelegate.checkServerTrusted(chain, authType, host); + if (mDelegate != null) { + return mDelegate.checkServerTrusted(chain, authType, host); + } else { + try { + return (List<X509Certificate>) mCheckServerTrusted.invoke(mTrustManager, chain, + authType, host); + } catch (IllegalAccessException e) { + throw new CertificateException("Failed to call checkServerTrusted", e); + } catch (InvocationTargetException e) { + if (e.getCause() instanceof CertificateException) { + throw (CertificateException) e.getCause(); + } + if (e.getCause() instanceof RuntimeException) { + throw (RuntimeException) e.getCause(); + } + throw new CertificateException("checkServerTrusted failed", e.getCause()); + } + } } /** @@ -80,7 +125,21 @@ public class X509TrustManagerExtensions { * otherwise. */ public boolean isUserAddedCertificate(X509Certificate cert) { - return mDelegate.isUserAddedCertificate(cert); + if (mDelegate != null) { + return mDelegate.isUserAddedCertificate(cert); + } else { + try { + return (Boolean) mIsUserAddedCertificate.invoke(mTrustManager, cert); + } catch (IllegalAccessException e) { + throw new RuntimeException("Failed to call isUserAddedCertificate", e); + } catch (InvocationTargetException e) { + if (e.getCause() instanceof RuntimeException) { + throw (RuntimeException) e.getCause(); + } else { + throw new RuntimeException("isUserAddedCertificate failed", e.getCause()); + } + } + } } /** diff --git a/core/java/android/security/net/config/NetworkSecurityConfig.java b/core/java/android/security/net/config/NetworkSecurityConfig.java index 503854ed64ff..8906f9b670d4 100644 --- a/core/java/android/security/net/config/NetworkSecurityConfig.java +++ b/core/java/android/security/net/config/NetworkSecurityConfig.java @@ -41,7 +41,7 @@ public final class NetworkSecurityConfig { private final List<CertificatesEntryRef> mCertificatesEntryRefs; private Set<TrustAnchor> mAnchors; private final Object mAnchorsLock = new Object(); - private X509TrustManager mTrustManager; + private NetworkSecurityTrustManager mTrustManager; private final Object mTrustManagerLock = new Object(); private NetworkSecurityConfig(boolean cleartextTrafficPermitted, boolean hstsEnforced, @@ -78,7 +78,7 @@ public final class NetworkSecurityConfig { return mPins; } - public X509TrustManager getTrustManager() { + public NetworkSecurityTrustManager getTrustManager() { synchronized(mTrustManagerLock) { if (mTrustManager == null) { mTrustManager = new NetworkSecurityTrustManager(this); diff --git a/core/java/android/security/net/config/NetworkSecurityTrustManager.java b/core/java/android/security/net/config/NetworkSecurityTrustManager.java index e69082d3deec..7f5b3ca27bf4 100644 --- a/core/java/android/security/net/config/NetworkSecurityTrustManager.java +++ b/core/java/android/security/net/config/NetworkSecurityTrustManager.java @@ -71,9 +71,28 @@ public class NetworkSecurityTrustManager implements X509TrustManager { @Override public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException { - List<X509Certificate> trustedChain = - mDelegate.checkServerTrusted(certs, authType, (String) null); + checkServerTrusted(certs, authType, null); + } + + /** + * Hostname aware version of {@link #checkServerTrusted(X509Certificate[], String)}. + * This interface is used by conscrypt and android.net.http.X509TrustManagerExtensions do not + * modify without modifying those callers. + */ + public List<X509Certificate> checkServerTrusted(X509Certificate[] certs, String authType, + String host) throws CertificateException { + List<X509Certificate> trustedChain = mDelegate.checkServerTrusted(certs, authType, host); checkPins(trustedChain); + return trustedChain; + } + + /** + * Check if the provided certificate is a user added certificate authority. + * This is required by android.net.http.X509TrustManagerExtensions. + */ + public boolean isUserAddedCertificate(X509Certificate cert) { + // TODO: Figure out the right way to handle this, and if it is still even used. + return false; } private void checkPins(List<X509Certificate> chain) throws CertificateException { diff --git a/core/java/android/security/net/config/RootTrustManager.java b/core/java/android/security/net/config/RootTrustManager.java index 1338b9ff97d4..b87bf1fe0695 100644 --- a/core/java/android/security/net/config/RootTrustManager.java +++ b/core/java/android/security/net/config/RootTrustManager.java @@ -18,6 +18,7 @@ package android.security.net.config; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; +import java.util.List; import javax.net.ssl.X509TrustManager; @@ -61,10 +62,24 @@ public class RootTrustManager implements X509TrustManager { config.getTrustManager().checkServerTrusted(certs, authType); } - public void checkServerTrusted(X509Certificate[] certs, String authType, String hostname) - throws CertificateException { + /** + * Hostname aware version of {@link #checkServerTrusted(X509Certificate[], String)}. + * This interface is used by conscrypt and android.net.http.X509TrustManagerExtensions do not + * modify without modifying those callers. + */ + public List<X509Certificate> checkServerTrusted(X509Certificate[] certs, String authType, + String hostname) throws CertificateException { NetworkSecurityConfig config = mConfig.getConfigForHostname(hostname); - config.getTrustManager().checkServerTrusted(certs, authType); + return config.getTrustManager().checkServerTrusted(certs, authType, hostname); + } + + /** + * Check if the provided certificate is a user added certificate authority. + * This is required by android.net.http.X509TrustManagerExtensions. + */ + public boolean isUserAddedCertificate(X509Certificate cert) { + // TODO: Figure out the right way to handle this, and if it is still even used. + return false; } @Override diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 66b05a20492f..461506bd6253 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -12968,10 +12968,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mPrivateFlags |= PFLAG_DIRTY; - // Release any resources in-case we don't end up drawing again - // as anything cached is no longer valid - resetDisplayList(); - if (invalidateCache) { mPrivateFlags |= PFLAG_INVALIDATED; mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index c54a574dfcb8..b5d994dc7c81 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -3975,6 +3975,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } ((Editable) mText).append(text, start, end); + + if (mAutoLinkMask != 0) { + boolean linksWereAdded = Linkify.addLinks((Spannable) mText, mAutoLinkMask); + // Do not change the movement method for text that support text selection as it + // would prevent an arbitrary cursor displacement. + if (linksWereAdded && mLinksClickable && !textCanBeSelected()) { + setMovementMethod(LinkMovementMethod.getInstance()); + } + } } private void updateTextColors() { diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml index 502378322cae..70abdf4920bb 100644 --- a/packages/PrintSpooler/res/values/strings.xml +++ b/packages/PrintSpooler/res/values/strings.xml @@ -149,6 +149,9 @@ <!-- Title for the prompt shown as a placeholder if no printers are found while not searching. [CHAR LIMIT=50] --> <string name="print_searching_for_printers">Searching for printers</string> + <!-- Title for the prompt shown as a placeholder if there are no print services. [CHAR LIMIT=50] --> + <string name="print_no_print_services">No print services enabled</string> + <!-- Title for the prompt shown as a placeholder if there are no printers while searching. [CHAR LIMIT=50] --> <string name="print_no_printers">No printers found</string> diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java index 3905bada8fe2..f4c15bd0690a 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java +++ b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java @@ -84,6 +84,11 @@ public final class SelectPrinterActivity extends Activity { private static final String EXTRA_PRINTER_ID = "EXTRA_PRINTER_ID"; + /** + * If there are any enabled print services + */ + private boolean mHasEnabledPrintServices; + private final ArrayList<PrintServiceInfo> mAddPrinterServices = new ArrayList<>(); @@ -175,10 +180,6 @@ public final class SelectPrinterActivity extends Activity { } }); - if (mAddPrinterServices.isEmpty()) { - menu.removeItem(R.id.action_add_printer); - } - return true; } @@ -230,6 +231,7 @@ public final class SelectPrinterActivity extends Activity { public void onResume() { super.onResume(); updateServicesWithAddPrinterActivity(); + updateEmptyView((DestinationAdapter)mListView.getAdapter()); invalidateOptionsMenu(); } @@ -258,6 +260,7 @@ public final class SelectPrinterActivity extends Activity { } private void updateServicesWithAddPrinterActivity() { + mHasEnabledPrintServices = true; mAddPrinterServices.clear(); // Get all enabled print services. @@ -266,6 +269,7 @@ public final class SelectPrinterActivity extends Activity { // No enabled print services - done. if (enabledServices.isEmpty()) { + mHasEnabledPrintServices = false; return; } @@ -324,7 +328,10 @@ public final class SelectPrinterActivity extends Activity { } TextView titleView = (TextView) findViewById(R.id.title); View progressBar = findViewById(R.id.progress_bar); - if (adapter.getUnfilteredCount() <= 0) { + if (!mHasEnabledPrintServices) { + titleView.setText(R.string.print_no_print_services); + progressBar.setVisibility(View.GONE); + } else if (adapter.getUnfilteredCount() <= 0) { titleView.setText(R.string.print_searching_for_printers); progressBar.setVisibility(View.VISIBLE); } else { diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java index a28601be03fa..85b8fcfb4a7f 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java @@ -270,7 +270,7 @@ public class RecentsTransitionHelper { int taskCount = tasks.size(); for (int i = taskCount - 1; i >= 0; i--) { Task t = tasks.get(i); - if (t.isFreeformTask()) { + if (t.isFreeformTask() || targetStackId == FREEFORM_WORKSPACE_STACK_ID) { TaskView tv = stackView.getChildViewForTask(t); if (tv == null) { // TODO: Create a different animation task rect for this case (though it should diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index ba6e9b1c1a4d..853a55c0f9f2 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -3103,6 +3103,9 @@ final class ActivityStack { // If the activity is PAUSING, we will complete the finish once // it is done pausing; else we can just directly finish it here. if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish not pausing: " + r); + if (r.visible) { + mWindowManager.setAppVisibility(r.appToken, false); + } return finishCurrentActivityLocked(r, FINISH_AFTER_PAUSE, oomAdj) == null; } else { if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish waiting for pause of: " + r); diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index f54fd834969a..e264c437241c 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -291,16 +291,18 @@ class DisplayContent { final ArrayList<Task> tasks = mStacks.get(stackNdx).getTasks(); for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { final Task task = tasks.get(taskNdx); - // We need to use the visible frame on the window for any touch-related tests. - // Can't use the task's bounds because the original task bounds might be adjusted - // to fit the content frame. For example, the presence of the IME adjusting the + final WindowState win = task.getTopVisibleAppMainWindow(); + if (win == null) { + continue; + } + // We need to use the task's dim bounds (which is derived from the visible + // bounds of its apps windows) for any touch-related tests. Can't use + // the task's original bounds because it might be adjusted to fit the + // content frame. For example, the presence of the IME adjusting the // windows frames when the app window is the IME target. - final WindowState win = task.getTopAppMainWindow(); - if (win != null) { - win.getVisibleBounds(mTmpRect); - if (mTmpRect.contains(x, y)) { - return task.mTaskId; - } + task.getDimBounds(mTmpRect); + if (mTmpRect.contains(x, y)) { + return task.mTaskId; } } } @@ -308,10 +310,10 @@ class DisplayContent { } /** - * Find the window whose outside touch area (for resizing) (x, y) falls within. + * Find the task whose outside touch area (for resizing) (x, y) falls within. * Returns null if the touch doesn't fall into a resizing area. */ - WindowState findWindowForControlPoint(int x, int y) { + Task findTaskForControlPoint(int x, int y) { final int delta = mService.dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics); for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { TaskStack stack = mStacks.get(stackNdx); @@ -325,24 +327,22 @@ class DisplayContent { return null; } - // We need to use the visible frame on the window for any touch-related - // tests. Can't use the task's bounds because the original task bounds - // might be adjusted to fit the content frame. (One example is when the - // task is put to top-left quadrant, the actual visible frame would not - // start at (0,0) after it's adjusted for the status bar.) - final WindowState win = task.getTopAppMainWindow(); - if (win != null) { - win.getVisibleBounds(mTmpRect); - mTmpRect.inset(-delta, -delta); - if (mTmpRect.contains(x, y)) { - mTmpRect.inset(delta, delta); - if (!mTmpRect.contains(x, y)) { - return win; - } - // User touched inside the task. No need to look further, - // focus transfer will be handled in ACTION_UP. - return null; + // We need to use the task's dim bounds (which is derived from the visible + // bounds of its apps windows) for any touch-related tests. Can't use + // the task's original bounds because it might be adjusted to fit the + // content frame. One example is when the task is put to top-left quadrant, + // the actual visible area would not start at (0,0) after it's adjusted + // for the status bar. + task.getDimBounds(mTmpRect); + mTmpRect.inset(-delta, -delta); + if (mTmpRect.contains(x, y)) { + mTmpRect.inset(delta, delta); + if (!mTmpRect.contains(x, y)) { + return task; } + // User touched inside the task. No need to look further, + // focus transfer will be handled in ACTION_UP. + return null; } } } @@ -351,12 +351,18 @@ class DisplayContent { void setTouchExcludeRegion(Task focusedTask) { mTouchExcludeRegion.set(mBaseDisplayRect); - WindowList windows = getWindowList(); final int delta = mService.dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics); - for (int i = windows.size() - 1; i >= 0; --i) { - final WindowState win = windows.get(i); - final Task task = win.getTask(); - if (win.isVisibleLw() && task != null) { + boolean addBackFocusedTask = false; + for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { + TaskStack stack = mStacks.get(stackNdx); + final ArrayList<Task> tasks = stack.getTasks(); + for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { + final Task task = tasks.get(taskNdx); + final WindowState win = task.getTopVisibleAppMainWindow(); + if (win == null) { + continue; + } + /** * Exclusion region is the region that TapDetector doesn't care about. * Here we want to remove all non-focused tasks from the exclusion region. @@ -368,13 +374,17 @@ class DisplayContent { */ final boolean isFreeformed = task.inFreeformWorkspace(); if (task != focusedTask || isFreeformed) { - mTmpRect.set(win.mVisibleFrame); - mTmpRect.intersect(win.mVisibleInsets); - /** - * If the task is freeformed, enlarge the area to account for outside - * touch area for resize. - */ + task.getDimBounds(mTmpRect); if (isFreeformed) { + // If we're removing a freeform, focused app from the exclusion region, + // we need to add back its touchable frame later. Remember the touchable + // frame now. + if (task == focusedTask) { + addBackFocusedTask = true; + mTmpRect2.set(mTmpRect); + } + // If the task is freeformed, enlarge the area to account for outside + // touch area for resize. mTmpRect.inset(-delta, -delta); // Intersect with display content rect. If we have system decor (status bar/ // navigation bar), we want to exclude that from the tap detection. @@ -385,17 +395,14 @@ class DisplayContent { } mTouchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE); } - /** - * If we removed the focused task above, add it back and only leave its - * outside touch area in the exclusion. TapDectector is not interested in - * any touch inside the focused task itself. - */ - if (task == focusedTask && isFreeformed) { - mTmpRect.inset(delta, delta); - mTouchExcludeRegion.op(mTmpRect, Region.Op.UNION); - } } } + // If we removed the focused task above, add it back and only leave its + // outside touch area in the exclusion. TapDectector is not interested in + // any touch inside the focused task itself. + if (addBackFocusedTask) { + mTouchExcludeRegion.op(mTmpRect2, Region.Op.UNION); + } if (mTapDetector != null) { mTapDetector.setTouchExcludeRegion(mTouchExcludeRegion); } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 1b8648899a62..46cd7cd5b0aa 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -284,7 +284,12 @@ class Task implements DimLayer.DimLayerUser { boolean getMaxVisibleBounds(Rect out) { boolean foundTop = false; for (int i = mAppTokens.size() - 1; i >= 0; i--) { - final WindowState win = mAppTokens.get(i).findMainWindow(); + final AppWindowToken token = mAppTokens.get(i); + // skip hidden (or about to hide) apps + if (token.mIsExiting || token.clientHidden || token.hiddenRequested) { + continue; + } + final WindowState win = token.findMainWindow(); if (win == null) { continue; } @@ -413,14 +418,20 @@ class Task implements DimLayer.DimLayerUser { return mStack != null && mStack.mStackId == DOCKED_STACK_ID; } - WindowState getTopAppMainWindow() { - final int tokensCount = mAppTokens.size(); - return tokensCount > 0 ? mAppTokens.get(tokensCount - 1).findMainWindow() : null; + WindowState getTopVisibleAppMainWindow() { + final AppWindowToken token = getTopVisibleAppToken(); + return token != null ? token.findMainWindow() : null; } - AppWindowToken getTopAppWindowToken() { - final int tokensCount = mAppTokens.size(); - return tokensCount > 0 ? mAppTokens.get(tokensCount - 1) : null; + AppWindowToken getTopVisibleAppToken() { + for (int i = mAppTokens.size() - 1; i >= 0; i--) { + final AppWindowToken token = mAppTokens.get(i); + // skip hidden (or about to hide) apps + if (!token.mIsExiting && !token.clientHidden && !token.hiddenRequested) { + return token; + } + } + return null; } @Override diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java index dd47e7a46777..f5e4e3be3477 100644 --- a/services/core/java/com/android/server/wm/TaskPositioner.java +++ b/services/core/java/com/android/server/wm/TaskPositioner.java @@ -332,30 +332,34 @@ class TaskPositioner implements DimLayer.DimLayerUser { + ", {" + startX + ", " + startY + "}"); } mCtrlType = CTRL_NONE; + mTask = win.getTask(); + mStartDragX = startX; + mStartDragY = startY; + + // Use the dim bounds, not the original task bounds. The cursor + // movement should be calculated relative to the visible bounds. + // Also, use the dim bounds of the task which accounts for + // multiple app windows. Don't use any bounds from win itself as it + // may not be the same size as the task. + mTask.getDimBounds(mTmpRect); + if (resize) { - final Rect visibleFrame = win.mVisibleFrame; - if (startX < visibleFrame.left) { + if (startX < mTmpRect.left) { mCtrlType |= CTRL_LEFT; } - if (startX > visibleFrame.right) { + if (startX > mTmpRect.right) { mCtrlType |= CTRL_RIGHT; } - if (startY < visibleFrame.top) { + if (startY < mTmpRect.top) { mCtrlType |= CTRL_TOP; } - if (startY > visibleFrame.bottom) { + if (startY > mTmpRect.bottom) { mCtrlType |= CTRL_BOTTOM; } mResizing = true; } - mTask = win.getTask(); - mStartDragX = startX; - mStartDragY = startY; - - // Use the visible bounds, not the original task bounds. The cursor - // movement should be calculated relative to the visible bounds. - mWindowOriginalBounds.set(win.mVisibleFrame); + mWindowOriginalBounds.set(mTmpRect); } private void endDragLocked() { diff --git a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java index 1fe359e1edc2..f5b83bbb4f8b 100644 --- a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java +++ b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java @@ -90,11 +90,11 @@ public class TaskTapPointerEventListener implements PointerEventListener { case MotionEvent.ACTION_HOVER_MOVE: { final int x = (int) motionEvent.getX(); final int y = (int) motionEvent.getY(); - final WindowState window = mDisplayContent.findWindowForControlPoint(x, y); - if (window == null) { + final Task task = mDisplayContent.findTaskForControlPoint(x, y); + if (task == null) { break; } - window.getVisibleBounds(mTmpRect); + task.getDimBounds(mTmpRect); if (!mTmpRect.isEmpty() && !mTmpRect.contains(x, y)) { int iconShape = STYLE_DEFAULT; if (x < mTmpRect.left) { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index f17698c47f2e..a22f8213e15d 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -7069,15 +7069,16 @@ public class WindowManagerService extends IWindowManager.Stub } private void startResizingTask(DisplayContent displayContent, int startX, int startY) { - WindowState win = null; + Task task = null; synchronized (mWindowMap) { - win = displayContent.findWindowForControlPoint(startX, startY); - if (win == null || !startPositioningLocked(win, true /*resize*/, startX, startY)) { + task = displayContent.findTaskForControlPoint(startX, startY); + if (task == null || !startPositioningLocked( + task.getTopVisibleAppMainWindow(), true /*resize*/, startX, startY)) { return; } } try { - mActivityManager.setFocusedTask(win.getTask().mTaskId); + mActivityManager.setFocusedTask(task.mTaskId); } catch(RemoteException e) {} } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 18bb4ca91557..673c21ff9931 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -1708,7 +1708,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { Task task = getTask(); if (task == null || task.inHomeStack() - || task.getTopAppWindowToken() != mAppToken) { + || task.getTopVisibleAppToken() != mAppToken) { // Don't save surfaces for home stack apps. These usually resume and draw // first frame very fast. Saving surfaces are mostly a waste of memory. // Don't save if the window is not the topmost window. diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index a3bb320f0b97..decfb342acad 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -16,7 +16,9 @@ package com.android.server.wm; +import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; +import static android.view.WindowManager.LayoutParams.FLAG_SCALED; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static com.android.server.wm.WindowManagerService.DEBUG_ANIM; import static com.android.server.wm.WindowManagerService.DEBUG_LAYERS; @@ -24,12 +26,12 @@ import static com.android.server.wm.WindowManagerService.DEBUG_ORIENTATION; import static com.android.server.wm.WindowManagerService.DEBUG_STARTING_WINDOW; import static com.android.server.wm.WindowManagerService.DEBUG_SURFACE_TRACE; import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY; -import static com.android.server.wm.WindowManagerService.localLOGV; import static com.android.server.wm.WindowManagerService.SHOW_LIGHT_TRANSACTIONS; import static com.android.server.wm.WindowManagerService.SHOW_SURFACE_ALLOC; import static com.android.server.wm.WindowManagerService.SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER; -import static com.android.server.wm.WindowState.*; +import static com.android.server.wm.WindowManagerService.localLOGV; +import static com.android.server.wm.WindowState.DRAG_RESIZE_MODE_FREEFORM; import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE; import static com.android.server.wm.WindowSurfacePlacer.SET_TURN_ON_SCREEN; @@ -37,7 +39,6 @@ import android.content.Context; import android.graphics.Matrix; import android.graphics.PixelFormat; import android.graphics.Point; -import android.graphics.PointF; import android.graphics.Rect; import android.graphics.Region; import android.os.Debug; @@ -47,12 +48,10 @@ import android.view.Display; import android.view.DisplayInfo; import android.view.MagnificationSpec; import android.view.Surface.OutOfResourcesException; -import android.view.Surface; import android.view.SurfaceControl; -import android.view.SurfaceSession; import android.view.WindowManager; -import android.view.WindowManagerPolicy; import android.view.WindowManager.LayoutParams; +import android.view.WindowManagerPolicy; import android.view.animation.Animation; import android.view.animation.AnimationSet; import android.view.animation.AnimationUtils; @@ -61,7 +60,6 @@ import android.view.animation.Transformation; import com.android.server.wm.WindowManagerService.H; import java.io.PrintWriter; -import java.util.ArrayList; /** * Keep track of animations and surface operations for a single WindowState. @@ -183,6 +181,8 @@ class WindowStateAnimator { int mAttrType; + private final Rect mTmpSize = new Rect(); + WindowStateAnimator(final WindowState win) { final WindowManagerService service = win.mService; @@ -442,7 +442,7 @@ class WindowStateAnimator { if (!isWindowAnimating()) { //TODO (multidisplay): Accessibility is supported only for the default display. if (mService.mAccessibilityController != null - && mWin.getDisplayId() == Display.DEFAULT_DISPLAY) { + && mWin.getDisplayId() == DEFAULT_DISPLAY) { mService.mAccessibilityController.onSomeWindowResizedOrMovedLocked(); } } @@ -581,52 +581,16 @@ class WindowStateAnimator { flags |= SurfaceControl.SECURE; } - float left = w.mFrame.left + w.mXOffset; - float top = w.mFrame.top + w.mYOffset; - - int width; - int height; - if ((attrs.flags & LayoutParams.FLAG_SCALED) != 0) { - // for a scaled surface, we always want the requested - // size. - width = w.mRequestedWidth; - height = w.mRequestedHeight; - } else { - // When we're doing a drag-resizing, request a surface that's fullscreen size, - // so that we don't need to reallocate during the process. This also prevents - // buffer drops due to size mismatch. - final DisplayInfo displayInfo = w.getDisplayInfo(); - if (displayInfo != null && w.isDragResizing()) { - left = 0; - top = 0; - width = displayInfo.logicalWidth; - height = displayInfo.logicalHeight; - } else { - width = w.mCompatFrame.width(); - height = w.mCompatFrame.height(); - } - } - - // Something is wrong and SurfaceFlinger will not like this, - // try to revert to sane values - if (width <= 0) { - width = 1; - } - if (height <= 0) { - height = 1; - } - - // Adjust for surface insets. - width += attrs.surfaceInsets.left + attrs.surfaceInsets.right; - height += attrs.surfaceInsets.top + attrs.surfaceInsets.bottom; - left -= attrs.surfaceInsets.left; - top -= attrs.surfaceInsets.top; + mTmpSize.set(w.mFrame.left + w.mXOffset, w.mFrame.top + w.mYOffset, 0, 0); + calculateSurfaceBounds(w, attrs); + final int width = mTmpSize.width(); + final int height = mTmpSize.height(); if (DEBUG_VISIBILITY) { Slog.v(TAG, "Creating surface in session " + mSession.mSurfaceSession + " window " + this + " w=" + width + " h=" + height - + " x=" + left + " y=" + top + + " x=" + mTmpSize.left + " y=" + mTmpSize.top + " format=" + attrs.format + " flags=" + flags); } @@ -692,15 +656,15 @@ class WindowStateAnimator { Slog.i(TAG, ">>> OPEN TRANSACTION createSurfaceLocked"); WindowManagerService.logSurface(w, "CREATE pos=(" + w.mFrame.left + "," + w.mFrame.top + ") (" - + w.mCompatFrame.width() + "x" + w.mCompatFrame.height() - + "), layer=" + mAnimLayer + " HIDE", null); + + width + "x" + height + "), layer=" + mAnimLayer + " HIDE", null); } // Start a new transaction and apply position & offset. final int layerStack = w.getDisplayContent().getDisplay().getLayerStack(); if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w, - "POS " + left + ", " + top, null); - mSurfaceController.setPositionAndLayer(left, top, layerStack, mAnimLayer); + "POS " + mTmpSize.left + ", " + mTmpSize.top, null); + mSurfaceController.setPositionAndLayer(mTmpSize.left, mTmpSize.top, layerStack, + mAnimLayer); mLastHidden = true; if (WindowManagerService.localLOGV) Slog.v( @@ -709,6 +673,57 @@ class WindowStateAnimator { return mSurfaceController; } + private void calculateSurfaceBounds(WindowState w, LayoutParams attrs) { + if ((attrs.flags & FLAG_SCALED) != 0) { + // For a scaled surface, we always want the requested size. + mTmpSize.right = mTmpSize.left + w.mRequestedWidth; + mTmpSize.bottom = mTmpSize.top + w.mRequestedHeight; + } else { + // When we're doing a drag-resizing, request a surface that's fullscreen size, + // so that we don't need to reallocate during the process. This also prevents + // buffer drops due to size mismatch. + if (w.isDragResizing()) { + if (w.getResizeMode() == DRAG_RESIZE_MODE_FREEFORM) { + mTmpSize.left = 0; + mTmpSize.top = 0; + } + final DisplayInfo displayInfo = w.getDisplayInfo(); + mTmpSize.right = mTmpSize.left + displayInfo.logicalWidth; + mTmpSize.bottom = mTmpSize.top + displayInfo.logicalHeight; + } else { + mTmpSize.right = mTmpSize.left + w.mCompatFrame.width(); + mTmpSize.bottom = mTmpSize.top + w.mCompatFrame.height(); + } + } + + // Something is wrong and SurfaceFlinger will not like this, try to revert to sane values. + if (mTmpSize.width() < 1) { + Slog.w(TAG, "Width of " + w + " is not positive " + mTmpSize.width()); + mTmpSize.right = mTmpSize.left + 1; + } + if (mTmpSize.height() < 1) { + Slog.w(TAG, "Height of " + w + " is not positive " + mTmpSize.height()); + mTmpSize.bottom = mTmpSize.top + 1; + } + + final int displayId = w.getDisplayId(); + float scale = 1.0f; + // Magnification is supported only for the default display. + if (mService.mAccessibilityController != null && displayId == DEFAULT_DISPLAY) { + final MagnificationSpec spec = + mService.mAccessibilityController.getMagnificationSpecForWindowLocked(w); + if (spec != null && !spec.isNop()) { + scale = spec.scale; + } + } + + // Adjust for surface insets. + mTmpSize.left -= scale * attrs.surfaceInsets.left; + mTmpSize.top -= scale * attrs.surfaceInsets.top; + mTmpSize.right += scale * (attrs.surfaceInsets.left + attrs.surfaceInsets.right); + mTmpSize.bottom += scale * (attrs.surfaceInsets.top + attrs.surfaceInsets.bottom); + } + void destroySurfaceLocked() { final AppWindowToken wtoken = mWin.mAppToken; if (wtoken != null) { @@ -891,7 +906,7 @@ class WindowStateAnimator { tmpMatrix.postTranslate(frame.left + mWin.mXOffset, frame.top + mWin.mYOffset); //TODO (multidisplay): Magnification is supported only for the default display. - if (mService.mAccessibilityController != null && displayId == Display.DEFAULT_DISPLAY) { + if (mService.mAccessibilityController != null && displayId == DEFAULT_DISPLAY) { MagnificationSpec spec = mService.mAccessibilityController .getMagnificationSpecForWindowLocked(mWin); if (spec != null && !spec.isNop()) { @@ -974,7 +989,7 @@ class WindowStateAnimator { MagnificationSpec spec = null; //TODO (multidisplay): Magnification is supported only for the default display. - if (mService.mAccessibilityController != null && displayId == Display.DEFAULT_DISPLAY) { + if (mService.mAccessibilityController != null && displayId == DEFAULT_DISPLAY) { spec = mService.mAccessibilityController.getMagnificationSpecForWindowLocked(mWin); } if (spec != null) { @@ -1157,65 +1172,12 @@ class WindowStateAnimator { void setSurfaceBoundariesLocked(final boolean recoveringMemory) { final WindowState w = mWin; - float left = w.mShownPosition.x; - float top = w.mShownPosition.y; - - int width; - int height; - if ((w.mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) { - // for a scaled surface, we always want the requested - // size. - width = w.mRequestedWidth; - height = w.mRequestedHeight; - } else { - // When we're doing a drag-resizing, request a surface that's fullscreen size, - // so that we don't need to reallocate during the process. This also prevents - // buffer drops due to size mismatch. - final DisplayInfo displayInfo = w.getDisplayInfo(); - - // In freeform resize mode, put surface at 0/0. - if (w.isDragResizing() && w.getResizeMode() == DRAG_RESIZE_MODE_FREEFORM) { - left = 0; - top = 0; - } - if (displayInfo != null && w.isDragResizing()) { - width = displayInfo.logicalWidth; - height = displayInfo.logicalHeight; - } else { - width = w.mCompatFrame.width(); - height = w.mCompatFrame.height(); - } - } - - // Something is wrong and SurfaceFlinger will not like this, - // try to revert to sane values - if (width < 1) { - width = 1; - } - if (height < 1) { - height = 1; - } - - // Adjust for surface insets. - final LayoutParams attrs = w.getAttrs(); - final int displayId = w.getDisplayId(); - float scale = 1.0f; - // Magnification is supported only for the default display. - if (mService.mAccessibilityController != null && displayId == Display.DEFAULT_DISPLAY) { - MagnificationSpec spec = - mService.mAccessibilityController.getMagnificationSpecForWindowLocked(w); - if (spec != null && !spec.isNop()) { - scale = spec.scale; - } - } - - width += scale * (attrs.surfaceInsets.left + attrs.surfaceInsets.right); - height += scale * (attrs.surfaceInsets.top + attrs.surfaceInsets.bottom); - left -= scale * attrs.surfaceInsets.left; - top -= scale * attrs.surfaceInsets.top; + mTmpSize.set(w.mShownPosition.x, w.mShownPosition.y, 0, 0); + calculateSurfaceBounds(w, w.getAttrs()); - mSurfaceController.setPositionInTransaction(left, top, recoveringMemory); - mSurfaceResized = mSurfaceController.setSizeInTransaction(width, height, + mSurfaceController.setPositionInTransaction(mTmpSize.left, mTmpSize.top, recoveringMemory); + mSurfaceResized = mSurfaceController.setSizeInTransaction( + mTmpSize.width(), mTmpSize.height(), mDsDx * w.mHScale, mDtDx * w.mVScale, mDsDy * w.mHScale, mDtDy * w.mVScale, recoveringMemory); @@ -1532,7 +1494,7 @@ class WindowStateAnimator { applyAnimationLocked(transit, true); //TODO (multidisplay): Magnification is supported only for the default display. if (mService.mAccessibilityController != null - && mWin.getDisplayId() == Display.DEFAULT_DISPLAY) { + && mWin.getDisplayId() == DEFAULT_DISPLAY) { mService.mAccessibilityController.onWindowTransitionLocked(mWin, transit); } } diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java index 5db1bde5f3f0..723e8278bcc0 100644 --- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java +++ b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java @@ -23,6 +23,7 @@ import com.android.ide.common.rendering.api.ResourceReference; import com.android.ide.common.rendering.api.ResourceValue; import com.android.layoutlib.bridge.Bridge; import com.android.layoutlib.bridge.BridgeConstants; +import com.android.layoutlib.bridge.MockView; import com.android.layoutlib.bridge.android.BridgeContext; import com.android.layoutlib.bridge.android.BridgeXmlBlockParser; import com.android.layoutlib.bridge.android.support.DrawerLayoutUtil; @@ -126,6 +127,9 @@ public final class BridgeInflater extends LayoutInflater { if (view == null) { view = loadCustomView(name, attrs); } + } catch (InflateException e) { + // Don't catch the InflateException below as that results in hiding the real cause. + throw e; } catch (Exception e) { // Wrap the real exception in a ClassNotFoundException, so that the calling method // can deal with it. @@ -154,23 +158,30 @@ public final class BridgeInflater extends LayoutInflater { } ta.recycle(); } - final Object lastContext = mConstructorArgs[0]; - mConstructorArgs[0] = context; - // try to load the class from using the custom view loader - try { - view = loadCustomView(name, attrs); - } catch (Exception e2) { - // Wrap the real exception in an InflateException so that the calling - // method can deal with it. - InflateException exception = new InflateException(); - if (!e2.getClass().equals(ClassNotFoundException.class)) { - exception.initCause(e2); - } else { - exception.initCause(e); + if (!(e.getCause() instanceof ClassNotFoundException)) { + // There is some unknown inflation exception in inflating a View that was found. + view = new MockView(context, attrs); + ((MockView) view).setText(name); + Bridge.getLog().error(LayoutLog.TAG_BROKEN, e.getMessage(), e, null); + } else { + final Object lastContext = mConstructorArgs[0]; + mConstructorArgs[0] = context; + // try to load the class from using the custom view loader + try { + view = loadCustomView(name, attrs); + } catch (Exception e2) { + // Wrap the real exception in an InflateException so that the calling + // method can deal with it. + InflateException exception = new InflateException(); + if (!e2.getClass().equals(ClassNotFoundException.class)) { + exception.initCause(e2); + } else { + exception.initCause(e); + } + throw exception; + } finally { + mConstructorArgs[0] = lastContext; } - throw exception; - } finally { - mConstructorArgs[0] = lastContext; } } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java index 44a9aad55daa..d392f213e5c8 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java @@ -17,39 +17,90 @@ package com.android.layoutlib.bridge; import android.content.Context; -import android.graphics.Canvas; import android.util.AttributeSet; import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; import android.widget.TextView; /** * Base class for mocked views. - * - * TODO: implement onDraw and draw a rectangle in a random color with the name of the class - * (or better the id of the view). + * <p/> + * FrameLayout with a single TextView. Doesn't allow adding any other views to itself. */ -public class MockView extends TextView { +public class MockView extends FrameLayout { + + private final TextView mView; + + public MockView(Context context) { + this(context, null); + } public MockView(Context context, AttributeSet attrs) { this(context, attrs, 0); } - public MockView(Context context, AttributeSet attrs, int defStyle) { - this(context, attrs, defStyle, 0); + public MockView(Context context, AttributeSet attrs, int defStyleAttr) { + this(context, attrs, defStyleAttr, 0); } public MockView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); - - setText(this.getClass().getSimpleName()); - setTextColor(0xFF000000); + mView = new TextView(context, attrs); + mView.setTextColor(0xFF000000); setGravity(Gravity.CENTER); + setText(getClass().getSimpleName()); + addView(mView); + setBackgroundColor(0xFF7F7F7F); + } + + // Only allow adding one TextView. + @Override + public void addView(View child) { + if (child == mView) { + super.addView(child); + } + } + + @Override + public void addView(View child, int index) { + if (child == mView) { + super.addView(child, index); + } } @Override - public void onDraw(Canvas canvas) { - canvas.drawARGB(0xFF, 0x7F, 0x7F, 0x7F); + public void addView(View child, int width, int height) { + if (child == mView) { + super.addView(child, width, height); + } + } + + @Override + public void addView(View child, ViewGroup.LayoutParams params) { + if (child == mView) { + super.addView(child, params); + } + } + + @Override + public void addView(View child, int index, ViewGroup.LayoutParams params) { + if (child == mView) { + super.addView(child, index, params); + } + } + + // The following methods are called by the IDE via reflection, and should be considered part + // of the API. + // Historically, MockView used to be a textView and had these methods. Now, we simply delegate + // them to the contained textView. + + public void setText(CharSequence text) { + mView.setText(text); + } - super.onDraw(canvas); + public void setGravity(int gravity) { + mView.setGravity(gravity); } } |