From 3c2c34bb039e92d68f466b7d194cbbe8241d8d60 Mon Sep 17 00:00:00 2001 From: Winson Date: Mon, 4 Apr 2016 17:47:41 -0700 Subject: [PATCH 1/3] Workaround to ensure that a SystemUI process is always available. - For a non-primary user, this CL will ensure that the SystemUI process is started when we are switched to the user. This allows us to maintain our current user-management model for Recents, which depends on this process for preloading and state management. Bug: 27175589 Change-Id: Id985fc2876e6daf06f303b44c0f9d1d3fd377842 --- packages/SystemUI/AndroidManifest.xml | 8 +++ .../android/systemui/SystemUIApplication.java | 11 ++++ .../SystemUISecondaryUserService.java | 60 +++++++++++++++++++ .../policy/UserSwitcherController.java | 20 +++++++ 4 files changed, 99 insertions(+) create mode 100644 packages/SystemUI/src/com/android/systemui/SystemUISecondaryUserService.java diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 983944628bd9d..e5411f351d2e7 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -184,6 +184,14 @@ android:exported="true" /> + + + + This method must only be called from the main thread.

+ */ + void startSecondaryUserServicesIfNeeded() { + startServicesIfNeeded(SERVICES_PER_USER); + } + private void startServicesIfNeeded(Class[] services) { if (mServicesStarted) { return; diff --git a/packages/SystemUI/src/com/android/systemui/SystemUISecondaryUserService.java b/packages/SystemUI/src/com/android/systemui/SystemUISecondaryUserService.java new file mode 100644 index 0000000000000..f619bfbcd047a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/SystemUISecondaryUserService.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2016 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.systemui; + +import android.app.ActivityManager; +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; +import android.os.Process; + +import java.io.FileDescriptor; +import java.io.PrintWriter; + +public class SystemUISecondaryUserService extends Service { + + @Override + public void onCreate() { + super.onCreate(); + ((SystemUIApplication) getApplication()).startSecondaryUserServicesIfNeeded(); + } + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + SystemUI[] services = ((SystemUIApplication) getApplication()).getServices(); + if (args == null || args.length == 0) { + for (SystemUI ui: services) { + pw.println("dumping service: " + ui.getClass().getName()); + ui.dump(fd, pw, args); + } + } else { + String svc = args[0]; + for (SystemUI ui: services) { + String name = ui.getClass().getName(); + if (name.endsWith(svc)) { + ui.dump(fd, pw, args); + } + } + } + } +} + diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java index ab44b6a277eee..ea0bdf29c25c2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -23,6 +23,7 @@ import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; +import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; @@ -52,6 +53,7 @@ import com.android.settingslib.RestrictedLockUtils; import com.android.systemui.BitmapHelper; import com.android.systemui.GuestResumeSessionReceiver; import com.android.systemui.R; +import com.android.systemui.SystemUISecondaryUserService; import com.android.systemui.qs.QSTile; import com.android.systemui.qs.tiles.UserDetailView; import com.android.systemui.statusbar.phone.ActivityStarter; @@ -101,6 +103,8 @@ public class UserSwitcherController { private boolean mSimpleUserSwitcher; private boolean mAddUsersWhenLocked; private boolean mPauseRefreshUsers; + private int mSecondaryUser = UserHandle.USER_NULL; + private Intent mSecondaryUserServiceIntent; private SparseBooleanArray mForcePictureLoadForUserId = new SparseBooleanArray(2); public UserSwitcherController(Context context, KeyguardMonitor keyguardMonitor, @@ -121,6 +125,8 @@ public class UserSwitcherController { mContext.registerReceiverAsUser(mReceiver, UserHandle.SYSTEM, filter, null /* permission */, null /* scheduler */); + mSecondaryUserServiceIntent = new Intent(context, SystemUISecondaryUserService.class); + filter = new IntentFilter(); filter.addAction(ACTION_REMOVE_GUEST); filter.addAction(ACTION_LOGOUT_USER); @@ -477,6 +483,20 @@ public class UserSwitcherController { } notifyAdapters(); + // Disconnect from the old secondary user's service + if (mSecondaryUser != UserHandle.USER_NULL) { + context.stopServiceAsUser(mSecondaryUserServiceIntent, + UserHandle.of(mSecondaryUser)); + mSecondaryUser = UserHandle.USER_NULL; + } + // Connect to the new secondary user's service (purely to ensure that a persistent + // SystemUI application is created for that user) + if (userInfo != null && !userInfo.isPrimary()) { + context.startServiceAsUser(mSecondaryUserServiceIntent, + UserHandle.of(userInfo.id)); + mSecondaryUser = userInfo.id; + } + if (UserManager.isSplitSystemUser() && userInfo != null && !userInfo.isGuest() && userInfo.id != UserHandle.USER_SYSTEM) { showLogoutNotification(currentId); From aeb298c4db913b376fb6053ec30c132a93e04635 Mon Sep 17 00:00:00 2001 From: Winson Date: Tue, 5 Apr 2016 13:08:11 -0700 Subject: [PATCH 2/3] Fixing bad regression in alt-tab layout. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Removing the notion of drawing the task header thumbnail on preload. This would not work because we could not know the stack state until showRecents() is actually called. Instead, we keep a cached thumbnail bitmap that we draw into when we start the activity, which is only updated when the layout changes. - Ensuring that with the smaller task views in the focused layout overlap and do not show a gap between them (this was introduced when the task views were made smaller to show more of the task behind it) - Ensure that both alt-tab and paging both default to focused state - Always reset the stack layout to clear the task overrides so that we don’t inadvertently get overrides when alt-tabbing Bug: 28014191 Change-Id: Ibc93597e9c027ce5abd65a8b77c0628864814c9b --- packages/SystemUI/res/values/config.xml | 2 +- .../android/systemui/recents/RecentsImpl.java | 158 ++++++------------ .../systemui/recents/tv/RecentsTvImpl.java | 2 +- .../views/TaskStackAnimationHelper.java | 3 +- .../views/TaskStackLayoutAlgorithm.java | 32 +++- 5 files changed, 86 insertions(+), 111 deletions(-) diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index fd051b1b371fa..6ce2a5dfb16c5 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -178,7 +178,7 @@ -3 - 3 + 2 diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java index 4dae7460f30ab..aba05aa386191 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java @@ -144,7 +144,6 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener // Task launching Rect mTaskStackBounds = new Rect(); - Rect mLastTaskViewBounds = new Rect(); TaskViewTransform mTmpTransform = new TaskViewTransform(); int mStatusBarHeight; int mNavBarHeight; @@ -169,8 +168,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener } }); - protected Bitmap mThumbnailTransitionBitmapCache; - Task mThumbnailTransitionBitmapCacheKey; + protected Bitmap mThumbTransitionBitmapCache; public RecentsImpl(Context context) { mContext = context; @@ -186,7 +184,6 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener // Initialize the static configuration resources reloadHeaderBarLayout(); - updateHeaderBarLayout(null /* stack */); // When we start, preload the data associated with the previous recent tasks. // We can use a new plan since the caches will be the same. @@ -201,12 +198,11 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener } public void onBootCompleted() { - updateHeaderBarLayout(null /* stack */); + // Do nothing } public void onConfigurationChanged() { reloadHeaderBarLayout(); - updateHeaderBarLayout(null /* stack */); } /** @@ -368,9 +364,14 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener loader.preloadTasks(sInstanceLoadPlan, topTask.id, topTaskHome.value); TaskStack stack = sInstanceLoadPlan.getTaskStack(); if (stack.getTaskCount() > 0) { - // We try and draw the thumbnail transition bitmap in parallel before - // toggle/show recents is called - preCacheThumbnailTransitionBitmapAsync(topTask, stack, mDummyStackView); + // Only preload the icon (but not the thumbnail since it may not have been taken for + // the pausing activity) + preloadIcon(topTask); + + // At this point, we don't know anything about the stack state. So only calculate + // the dimensions of the thumbnail that we need for the transition into Recents, but + // do not draw it until we construct the activity options when we start Recents + updateHeaderBarLayout(stack); } } } @@ -601,21 +602,30 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener if (stack != null) { stackLayout.getTaskStackBounds(windowRect, systemInsets.top, systemInsets.right, mTaskStackBounds); + stackLayout.reset(); stackLayout.initialize(windowRect, mTaskStackBounds, TaskStackLayoutAlgorithm.StackState.getStackStateForStack(stack)); mDummyStackView.setTasks(stack, false /* allowNotifyStackChanges */); - } - Rect taskViewBounds = stackLayout.getUntransformedTaskViewBounds(); - if (!taskViewBounds.equals(mLastTaskViewBounds)) { - mLastTaskViewBounds.set(taskViewBounds); + Rect taskViewBounds = stackLayout.getUntransformedTaskViewBounds(); int taskViewWidth = taskViewBounds.width(); synchronized (mHeaderBarLock) { - mHeaderBar.measure( - View.MeasureSpec.makeMeasureSpec(taskViewWidth, View.MeasureSpec.EXACTLY), - View.MeasureSpec.makeMeasureSpec(mTaskBarHeight, View.MeasureSpec.EXACTLY)); + if (mHeaderBar.getMeasuredWidth() != taskViewWidth || + mHeaderBar.getMeasuredHeight() != mTaskBarHeight) { + mHeaderBar.measure( + View.MeasureSpec.makeMeasureSpec(taskViewWidth, View.MeasureSpec.EXACTLY), + View.MeasureSpec.makeMeasureSpec(mTaskBarHeight, View.MeasureSpec.EXACTLY)); + } mHeaderBar.layout(0, 0, taskViewWidth, mTaskBarHeight); } + + // Update the transition bitmap to match the new header bar height + if (mThumbTransitionBitmapCache == null || + (mThumbTransitionBitmapCache.getWidth() != taskViewWidth) || + (mThumbTransitionBitmapCache.getHeight() != mTaskBarHeight)) { + mThumbTransitionBitmapCache = Bitmap.createBitmap(taskViewWidth, + mTaskBarHeight, Bitmap.Config.ARGB_8888); + } } } @@ -651,40 +661,6 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener Recents.getTaskLoader().loadTasks(mContext, sInstanceLoadPlan, launchOpts); } - /** - * Caches the header thumbnail used for a window animation asynchronously into - * {@link #mThumbnailTransitionBitmapCache}. - */ - private void preCacheThumbnailTransitionBitmapAsync(ActivityManager.RunningTaskInfo topTask, - TaskStack stack, TaskStackView stackView) { - preloadIcon(topTask); - - // Update the header bar if necessary - updateHeaderBarLayout(stack); - - // Update the destination rect - final Task toTask = new Task(); - final TaskViewTransform toTransform = getThumbnailTransitionTransform(stackView, toTask); - ForegroundThread.getHandler().postAtFrontOfQueue(new Runnable() { - @Override - public void run() { - final Bitmap transitionBitmap = drawThumbnailTransitionBitmap(toTask, toTransform); - if (transitionBitmap != null) { - mHandler.post(new Runnable() { - @Override - public void run() { - mThumbnailTransitionBitmapCache = transitionBitmap; - mThumbnailTransitionBitmapCacheKey = toTask; - } - }); - } else { - Log.e(TAG, "Could not load thumbnail for task: " + toTask + " at transform: " + - toTransform); - } - } - }); - } - /** * Creates the activity options for a unknown state->recents transition. */ @@ -724,9 +700,10 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener if (task.isFreeformTask()) { mTmpTransform = stackLayout.getStackTransformScreenCoordinates(task, stackScroller.getStackScroll(), mTmpTransform, null); + Bitmap thumbnail = drawThumbnailTransitionBitmap(task, mTmpTransform, + mThumbTransitionBitmapCache); Rect toTaskRect = new Rect(); mTmpTransform.rect.round(toTaskRect); - Bitmap thumbnail = getThumbnailBitmap(topTask, task, mTmpTransform); specs.add(new AppTransitionAnimationSpec(task.key.id, thumbnail, toTaskRect)); } } @@ -738,9 +715,10 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener // Update the destination rect Task toTask = new Task(); TaskViewTransform toTransform = getThumbnailTransitionTransform(stackView, toTask); - RectF toTaskRect = toTransform.rect; - Bitmap thumbnail = getThumbnailBitmap(topTask, toTask, toTransform); + Bitmap thumbnail = drawThumbnailTransitionBitmap(toTask, toTransform, + mThumbTransitionBitmapCache); if (thumbnail != null) { + RectF toTaskRect = toTransform.rect; return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView, thumbnail, (int) toTaskRect.left, (int) toTaskRect.top, (int) toTaskRect.width(), (int) toTaskRect.height(), mHandler, null); @@ -750,22 +728,6 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener } } - private Bitmap getThumbnailBitmap(ActivityManager.RunningTaskInfo topTask, Task toTask, - TaskViewTransform toTransform) { - Bitmap thumbnail; - if (mThumbnailTransitionBitmapCacheKey != null - && mThumbnailTransitionBitmapCacheKey.key != null - && mThumbnailTransitionBitmapCacheKey.key.equals(toTask.key)) { - thumbnail = mThumbnailTransitionBitmapCache; - mThumbnailTransitionBitmapCacheKey = null; - mThumbnailTransitionBitmapCache = null; - } else { - preloadIcon(topTask); - thumbnail = drawThumbnailTransitionBitmap(toTask, toTransform); - } - return thumbnail; - } - /** * Returns the transition rect for the given task id. */ @@ -793,26 +755,19 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener /** * Draws the header of a task used for the window animation into a bitmap. */ - private Bitmap drawThumbnailTransitionBitmap(Task toTask, TaskViewTransform toTransform) { + private Bitmap drawThumbnailTransitionBitmap(Task toTask, TaskViewTransform toTransform, + Bitmap thumbnail) { SystemServicesProxy ssp = Recents.getSystemServices(); if (toTransform != null && toTask.key != null) { - Bitmap thumbnail; synchronized (mHeaderBarLock) { - int toHeaderWidth = (int) toTransform.rect.width(); - int toHeaderHeight = (int) (mHeaderBar.getMeasuredHeight() * toTransform.scale); - if (toHeaderWidth <= 0 || toHeaderHeight <= 0) { - return null; - } boolean disabledInSafeMode = !toTask.isSystemApp && ssp.isInSafeMode(); mHeaderBar.onTaskViewSizeChanged((int) toTransform.rect.width(), (int) toTransform.rect.height()); - thumbnail = Bitmap.createBitmap(toHeaderWidth, toHeaderHeight, - Bitmap.Config.ARGB_8888); if (RecentsDebugFlags.Static.EnableTransitionThumbnailDebugMode) { thumbnail.eraseColor(0xFFff0000); } else { + thumbnail.eraseColor(0); Canvas c = new Canvas(thumbnail); - c.scale(toTransform.scale, toTransform.scale); // Workaround for b/27815919, reset the callback so that we do not trigger an // invalidate on the header bar as a result of updating the icon Drawable icon = mHeaderBar.getIconView().getDrawable(); @@ -854,6 +809,18 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener boolean hasRecentTasks = stack.getTaskCount() > 0; boolean useThumbnailTransition = (topTask != null) && !isTopTaskHome && hasRecentTasks; + // Update the launch state that we need in updateHeaderBarLayout() + launchState.launchedFromHome = !useThumbnailTransition; + launchState.launchedFromApp = useThumbnailTransition || mLaunchedWhileDocking; + launchState.launchedViaDockGesture = mLaunchedWhileDocking; + launchState.launchedViaDragGesture = mDraggingInRecents; + launchState.launchedToTaskId = (topTask != null) ? topTask.id : -1; + launchState.launchedWithAltTab = mTriggeredFromAltTab; + + // Preload the icon (this will be a null-op if we have preloaded the icon already in + // preloadRecents()) + preloadIcon(topTask); + // Update the header bar if necessary updateHeaderBarLayout(stack); @@ -861,44 +828,27 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener TaskStackLayoutAlgorithm.VisibilityReport stackVr = mDummyStackView.computeStackVisibilityReport(); - // Update the launch state - launchState.launchedFromHome = false; - launchState.launchedFromApp = mLaunchedWhileDocking; - launchState.launchedViaDockGesture = mLaunchedWhileDocking; - launchState.launchedToTaskId = (topTask != null) ? topTask.id : -1; - launchState.launchedWithAltTab = mTriggeredFromAltTab; + // Update the remaining launch state launchState.launchedNumVisibleTasks = stackVr.numVisibleTasks; launchState.launchedNumVisibleThumbnails = stackVr.numVisibleThumbnails; - launchState.launchedViaDragGesture = mDraggingInRecents; if (!animate) { startRecentsActivity(ActivityOptions.makeCustomAnimation(mContext, -1, -1)); return; } + ActivityOptions opts; if (useThumbnailTransition) { - launchState.launchedFromApp = true; - // Try starting with a thumbnail transition - ActivityOptions opts = getThumbnailTransitionActivityOptions(topTask, mDummyStackView); - if (opts != null) { - startRecentsActivity(opts); - } else { - // Fall through below to the non-thumbnail transition - useThumbnailTransition = false; - } - } - - if (!useThumbnailTransition) { - launchState.launchedFromHome = true; - + opts = getThumbnailTransitionActivityOptions(topTask, mDummyStackView); + } else { // If there is no thumbnail transition, but is launching from home into recents, then // use a quick home transition - ActivityOptions opts = hasRecentTasks - ? getHomeTransitionActivityOptions() - : getUnknownTransitionActivityOptions(); - startRecentsActivity(opts); + opts = hasRecentTasks + ? getHomeTransitionActivityOptions() + : getUnknownTransitionActivityOptions(); } + startRecentsActivity(opts); mLastToggleTime = SystemClock.elapsedRealtime(); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java index c1b47dcbb4e06..fb62affd6ceea 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java +++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java @@ -124,7 +124,7 @@ public class RecentsTvImpl extends RecentsImpl{ */ private ActivityOptions getThumbnailTransitionActivityOptionsForTV( ActivityManager.RunningTaskInfo topTask) { - Bitmap thumbnail = mThumbnailTransitionBitmapCache; + Bitmap thumbnail = mThumbTransitionBitmapCache; Rect rect = TaskCardView.getStartingCardThumbnailRect(mContext); if (thumbnail != null) { return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView, diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java index 1c433d8eb31c2..fe91f421c202c 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java @@ -456,7 +456,8 @@ public class TaskStackAnimationHelper { TaskStack stack = mStackView.getStack(); final float curScroll = stackScroller.getStackScroll(); - final float newScroll = stackLayout.getStackScrollForTask(newFocusedTask); + final float newScroll = stackScroller.getBoundedStackScroll( + stackLayout.getStackScrollForTask(newFocusedTask)); boolean willScrollToFront = newScroll > curScroll; boolean willScroll = Float.compare(newScroll, curScroll) != 0; diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java index 9eab0f60584f8..c16a9be462253 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java @@ -29,6 +29,7 @@ import android.view.ViewDebug; import com.android.systemui.R; import com.android.systemui.recents.Recents; +import com.android.systemui.recents.RecentsActivity; import com.android.systemui.recents.RecentsActivityLaunchState; import com.android.systemui.recents.RecentsConfiguration; import com.android.systemui.recents.RecentsDebugFlags; @@ -530,8 +531,12 @@ public class TaskStackLayoutAlgorithm { ? stack.indexOfStackTask(launchTask) : mNumStackTasks - 1; if (getInitialFocusState() == STATE_FOCUSED) { + int maxBottomOffset = mStackBottomOffset + mTaskRect.height(); + float maxBottomNormX = getNormalizedXFromFocusedY(maxBottomOffset, FROM_BOTTOM); + mFocusedRange.offset(0f); mMinScrollP = 0; - mMaxScrollP = Math.max(mMinScrollP, mNumStackTasks - 1); + mMaxScrollP = Math.max(mMinScrollP, (mNumStackTasks - 1) - + Math.max(0, mFocusedRange.getAbsoluteX(maxBottomNormX))); if (launchState.launchedFromHome) { mInitialScrollP = Utilities.clamp(launchTaskIndex, mMinScrollP, mMaxScrollP); } else { @@ -555,7 +560,10 @@ public class TaskStackLayoutAlgorithm { Math.max(0, mUnfocusedRange.getAbsoluteX(maxBottomNormX))); boolean scrollToFront = launchState.launchedFromHome || launchState.launchedViaDockGesture; - if (scrollToFront) { + if (launchState.launchedWithAltTab) { + mInitialScrollP = Utilities.clamp(launchTaskIndex, mMinScrollP, mMaxScrollP); + mInitialNormX = null; + } else if (scrollToFront) { mInitialScrollP = Utilities.clamp(launchTaskIndex, mMinScrollP, mMaxScrollP); mInitialNormX = null; } else { @@ -652,8 +660,9 @@ public class TaskStackLayoutAlgorithm { * Returns the default focus state. */ public int getInitialFocusState() { + RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState(); RecentsDebugFlags debugFlags = Recents.getDebugFlags(); - if (debugFlags.isPagingEnabled()) { + if (debugFlags.isPagingEnabled() || launchState.launchedWithAltTab) { return STATE_FOCUSED; } else { return STATE_UNFOCUSED; @@ -1026,6 +1035,18 @@ public class TaskStackLayoutAlgorithm { return mUnfocusedCurveInterpolator.getX(offsetPct); } + /** + * Returns the normalized x on the focused curve given an absolute Y position (relative to the + * stack height). + */ + private float getNormalizedXFromFocusedY(float y, @AnchorSide int fromSide) { + float offset = (fromSide == FROM_TOP) + ? mStackRect.height() - y + : y; + float offsetPct = offset / mStackRect.height(); + return mFocusedCurveInterpolator.getX(offsetPct); + } + /** * Creates a new path for the focused curve. */ @@ -1036,10 +1057,13 @@ public class TaskStackLayoutAlgorithm { float topPeekHeightPct = (float) mFocusedTopPeekHeight / mStackRect.height(); float bottomPeekHeightPct = (float) (mStackBottomOffset + mFocusedBottomPeekHeight) / mStackRect.height(); + float minBottomPeekHeightPct = (float) (mFocusedTopPeekHeight + mTaskRect.height() - + mMinMargin) / mStackRect.height(); Path p = new Path(); p.moveTo(0f, 1f); p.lineTo(0.5f, 1f - topPeekHeightPct); - p.lineTo(1f - (0.5f / mFocusedRange.relativeMax), bottomPeekHeightPct); + p.lineTo(1f - (0.5f / mFocusedRange.relativeMax), Math.max(1f - minBottomPeekHeightPct, + bottomPeekHeightPct)); p.lineTo(1f, 0f); return p; } From 5b3b4b43c9a6afa9d153915df4e6d5f2ade4e150 Mon Sep 17 00:00:00 2001 From: Winson Date: Tue, 5 Apr 2016 14:13:02 -0700 Subject: [PATCH 3/3] Remove the highlight on the overview button in the screen pinning dialog - Now that you just long press back, we should not indicate to the user that you need to long press both to exit screen pinning. Bug: 28024008 Change-Id: I1bad66e2b975f1f5943989d56348bc8e8b27fbbe --- .../res/layout/screen_pinning_request_buttons.xml | 15 --------------- .../screen_pinning_request_buttons_land.xml | 15 --------------- 2 files changed, 30 deletions(-) diff --git a/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml b/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml index 224a0a0fd8591..60112be21175f 100644 --- a/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml +++ b/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml @@ -109,21 +109,6 @@ android:paddingStart="@dimen/screen_pinning_request_frame_padding" android:paddingEnd="@dimen/screen_pinning_request_frame_padding" > - - - - - - - -