diff options
34 files changed, 599 insertions, 621 deletions
diff --git a/build.gradle b/build.gradle index 61c05e562..0030b8bfc 100644 --- a/build.gradle +++ b/build.gradle @@ -13,12 +13,12 @@ apply plugin: 'com.android.application' apply plugin: 'com.google.protobuf' android { - compileSdkVersion 27 - buildToolsVersion '27.0.0' + compileSdkVersion 28 + buildToolsVersion '28.0.0' defaultConfig { minSdkVersion 21 - targetSdkVersion 27 + targetSdkVersion 28 versionCode 1 versionName "1.0" @@ -102,7 +102,7 @@ repositories { jcenter() } -final String SUPPORT_LIBS_VERSION = '27.0.0-SNAPSHOT' +final String SUPPORT_LIBS_VERSION = '28.0.0-SNAPSHOT' dependencies { compile "com.android.support:support-v4:${SUPPORT_LIBS_VERSION}" compile "com.android.support:support-dynamic-animation:${SUPPORT_LIBS_VERSION}" diff --git a/proguard.flags b/proguard.flags index 987fb6f12..b8cade572 100644 --- a/proguard.flags +++ b/proguard.flags @@ -97,6 +97,11 @@ # support jar. -keep class android.support.v7.widget.RecyclerView { *; } +# LauncherAppTransitionManager +-keep class com.android.launcher3.LauncherAppTransitionManagerImpl { + public <init>(...); +} + -keep interface com.android.launcher3.userevent.nano.LauncherLogProto.** { *; } diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml new file mode 100644 index 000000000..94211c62f --- /dev/null +++ b/quickstep/res/values/config.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2018 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. +--> +<resources> + <string name="task_overlay_factory_class" translatable="false"></string> + +</resources> diff --git a/res/layout/predictions_view.xml b/quickstep/res/values/override.xml index 280290c6a..ba99d81c0 100644 --- a/res/layout/predictions_view.xml +++ b/quickstep/res/values/override.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2017 The Android Open Source Project +<!-- Copyright (C) 2018 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. @@ -13,7 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. --> -<com.android.launcher3.allapps.PredictionRowView - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="wrap_content" />
\ No newline at end of file + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_transition_manager_class" translatable="false">com.android.launcher3.LauncherAppTransitionManagerImpl</string> +</resources> + diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManager.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java index 47179c5a0..9968ca72c 100644 --- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManager.java +++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java @@ -26,6 +26,8 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; +import android.content.Context; +import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Matrix; @@ -55,11 +57,15 @@ import com.android.systemui.shared.system.WindowManagerWrapper; /** * Manages the opening and closing app transitions from Launcher. */ -public class LauncherAppTransitionManager { +public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManager { private static final String TAG = "LauncherTransition"; private static final int REFRESH_RATE_MS = 16; + private static final String CONTROL_REMOTE_APP_TRANSITION_PERMISSION = + "android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"; + + private static final int LAUNCHER_RESUME_START_DELAY = 150; private static final int CLOSING_TRANSITION_DURATION_MS = 350; // Progress = 0: All apps is fully pulled up, Progress = 1: All apps is fully pulled down. @@ -76,60 +82,79 @@ public class LauncherAppTransitionManager { private ImageView mFloatingView; private boolean mIsRtl; - public LauncherAppTransitionManager(Launcher launcher) { - mLauncher = launcher; - mDragLayer = launcher.getDragLayer(); - mDeviceProfile = launcher.getDeviceProfile(); + private Animator mCurrentAnimator; + + public LauncherAppTransitionManagerImpl(Context context) { + mLauncher = Launcher.getLauncher(context); + mDragLayer = mLauncher.getDragLayer(); + mDeviceProfile = mLauncher.getDeviceProfile(); - mIsRtl = Utilities.isRtl(launcher.getResources()); + mIsRtl = Utilities.isRtl(mLauncher.getResources()); - Resources res = launcher.getResources(); + Resources res = mLauncher.getResources(); mContentTransY = res.getDimensionPixelSize(R.dimen.content_trans_y); mWorkspaceTransY = res.getDimensionPixelSize(R.dimen.workspace_trans_y); } + private void setCurrentAnimator(Animator animator) { + if (mCurrentAnimator != null && mCurrentAnimator.isRunning()) { + mCurrentAnimator.cancel(); + } + mCurrentAnimator = animator; + } + /** * @return A Bundle with remote animations that controls how the window of the opening * targets are displayed. */ - public Bundle getActivityLauncherOptions(View v) { - RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mLauncher) { - @Override - public void onAnimationStart(RemoteAnimationTargetCompat[] targets, - Runnable finishedCallback) { - // Post at front of queue ignoring sync barriers to make sure it gets processed - // before the next frame. - postAtFrontOfQueueAsynchronously(v.getHandler(), () -> { - mAnimator = new AnimatorSet(); - mAnimator.play(getLauncherAnimators(v)); - mAnimator.play(getWindowAnimators(v, targets)); - mAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - // Reset launcher to normal state - v.setVisibility(View.VISIBLE); - ((ViewGroup) mDragLayer.getParent()).removeView(mFloatingView); - - mDragLayer.setAlpha(1f); - mDragLayer.setTranslationY(0f); - - View appsView = mLauncher.getAppsView(); - appsView.setAlpha(1f); - appsView.setTranslationY(0f); + @Override + public Bundle getActivityLaunchOptions(Launcher launcher, View v) { + if (hasControlRemoteAppTransitionPermission()) { + try { + RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mLauncher) { + @Override + public void onAnimationStart(RemoteAnimationTargetCompat[] targets, + Runnable finishedCallback) { + // Post at front of queue ignoring sync barriers to make sure it gets + // processed before the next frame. + postAtFrontOfQueueAsynchronously(v.getHandler(), () -> { + mAnimator = new AnimatorSet(); + setCurrentAnimator(mAnimator); + mAnimator.play(getLauncherAnimators(v)); + mAnimator.play(getWindowAnimators(v, targets)); + mAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + // Reset launcher to normal state + v.setVisibility(View.VISIBLE); + ((ViewGroup) mDragLayer.getParent()).removeView(mFloatingView); + + mDragLayer.setAlpha(1f); + mDragLayer.setTranslationY(0f); + + View appsView = mLauncher.getAppsView(); + appsView.setAlpha(1f); + appsView.setTranslationY(0f); + + finishedCallback.run(); + } + }); + mAnimator.start(); + // Because t=0 has the app icon in its original spot, we can skip the + // first frame and have the same movement one frame earlier. + mAnimator.setCurrentPlayTime(REFRESH_RATE_MS); + }); + } + }; - finishedCallback.run(); - } - }); - mAnimator.start(); - // Because t=0 has the app icon in its original spot, we can skip the first - // frame and have the same movement one frame earlier. - mAnimator.setCurrentPlayTime(REFRESH_RATE_MS); - }); + return ActivityOptionsCompat.makeRemoteAnimation( + new RemoteAnimationAdapterCompat(runner, 500, 380)).toBundle(); + } catch (NoClassDefFoundError e) { + // Gracefully fall back to default launch options if the user's platform doesn't + // have the latest changes. } - }; - - return ActivityOptionsCompat.makeRemoteAnimation( - new RemoteAnimationAdapterCompat(runner, 500, 380)).toBundle(); + } + return getDefaultActivityLaunchOptions(launcher, v); } /** @@ -149,7 +174,7 @@ public class LauncherAppTransitionManager { * Else: Animate the content so that it moves downwards and fades out. */ private AnimatorSet getLauncherContentAnimator(boolean show) { - AnimatorSet hideLauncher = new AnimatorSet(); + AnimatorSet launcherAnimator = new AnimatorSet(); float[] alphas = show ? new float[] {0, 1} @@ -161,6 +186,9 @@ public class LauncherAppTransitionManager { if (mLauncher.isInState(LauncherState.ALL_APPS) && !mDeviceProfile.isVerticalBarLayout()) { // All Apps in portrait mode is full screen, so we only animate AllAppsContainerView. View appsView = mLauncher.getAppsView(); + appsView.setAlpha(alphas[0]); + appsView.setTranslationY(trans[0]); + ObjectAnimator alpha = ObjectAnimator.ofFloat(appsView, View.ALPHA, alphas); alpha.setDuration(217); alpha.setInterpolator(Interpolators.LINEAR); @@ -168,9 +196,12 @@ public class LauncherAppTransitionManager { transY.setInterpolator(Interpolators.AGGRESSIVE_EASE); transY.setDuration(350); - hideLauncher.play(alpha); - hideLauncher.play(transY); + launcherAnimator.play(alpha); + launcherAnimator.play(transY); } else { + mDragLayer.setAlpha(alphas[0]); + mDragLayer.setTranslationY(trans[0]); + ObjectAnimator dragLayerAlpha = ObjectAnimator.ofFloat(mDragLayer, View.ALPHA, alphas); dragLayerAlpha.setDuration(217); dragLayerAlpha.setInterpolator(Interpolators.LINEAR); @@ -179,10 +210,10 @@ public class LauncherAppTransitionManager { dragLayerTransY.setInterpolator(Interpolators.AGGRESSIVE_EASE); dragLayerTransY.setDuration(350); - hideLauncher.play(dragLayerAlpha); - hideLauncher.play(dragLayerTransY); + launcherAnimator.play(dragLayerAlpha); + launcherAnimator.play(dragLayerTransY); } - return hideLauncher; + return launcherAnimator; } /** @@ -361,15 +392,22 @@ public class LauncherAppTransitionManager { /** * Registers remote animations used when closing apps to home screen. */ + @Override public void registerRemoteAnimations() { - RemoteAnimationDefinitionCompat definition = new RemoteAnimationDefinitionCompat(); - definition.addRemoteAnimation(WindowManagerWrapper.TRANSIT_WALLPAPER_OPEN, - new RemoteAnimationAdapterCompat(getWallpaperOpenRunner(), 0, - CLOSING_TRANSITION_DURATION_MS)); + if (hasControlRemoteAppTransitionPermission()) { + try { + RemoteAnimationDefinitionCompat definition = new RemoteAnimationDefinitionCompat(); + definition.addRemoteAnimation(WindowManagerWrapper.TRANSIT_WALLPAPER_OPEN, + new RemoteAnimationAdapterCompat(getWallpaperOpenRunner(), 0, + CLOSING_TRANSITION_DURATION_MS)); // TODO: App controlled transition for unlock to home TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER - new ActivityCompat(mLauncher).registerRemoteAnimations(definition); + new ActivityCompat(mLauncher).registerRemoteAnimations(definition); + } catch (NoClassDefFoundError e) { + // Gracefully fall back if the user's platform doesn't have the latest changes + } + } } /** @@ -385,11 +423,13 @@ public class LauncherAppTransitionManager { postAtFrontOfQueueAsynchronously(handler, () -> { // We use a separate transition for Overview mode. if (mLauncher.isInState(LauncherState.OVERVIEW)) { + setCurrentAnimator(null); finishedCallback.run(); return; } mAnimator = new AnimatorSet(); + setCurrentAnimator(mAnimator); mAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { @@ -465,7 +505,9 @@ public class LauncherAppTransitionManager { private AnimatorSet getLauncherResumeAnimation() { if (mLauncher.isInState(LauncherState.ALL_APPS) || mLauncher.getDeviceProfile().isVerticalBarLayout()) { - return getLauncherContentAnimator(true /* show */); + AnimatorSet contentAnimator = getLauncherContentAnimator(true /* show */); + contentAnimator.setStartDelay(LAUNCHER_RESUME_START_DELAY); + return contentAnimator; } else { AnimatorSet workspaceAnimator = new AnimatorSet(); mLauncher.getWorkspace().setTranslationY(mWorkspaceTransY); @@ -474,7 +516,7 @@ public class LauncherAppTransitionManager { View.TRANSLATION_Y, mWorkspaceTransY, 0)); workspaceAnimator.play(ObjectAnimator.ofFloat(mLauncher.getWorkspace(), View.ALPHA, 0, 1f)); - workspaceAnimator.setStartDelay(150); + workspaceAnimator.setStartDelay(LAUNCHER_RESUME_START_DELAY); workspaceAnimator.setDuration(333); workspaceAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); @@ -489,7 +531,7 @@ public class LauncherAppTransitionManager { Animator allAppsSlideIn = ObjectAnimator.ofFloat(allAppsController, ALL_APPS_PROGRESS, startY, slideEnd); - allAppsSlideIn.setStartDelay(150); + allAppsSlideIn.setStartDelay(LAUNCHER_RESUME_START_DELAY); allAppsSlideIn.setDuration(317); allAppsSlideIn.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); @@ -505,6 +547,11 @@ public class LauncherAppTransitionManager { } } + private boolean hasControlRemoteAppTransitionPermission() { + return mLauncher.checkSelfPermission(CONTROL_REMOTE_APP_TRANSITION_PERMISSION) + == PackageManager.PERMISSION_GRANTED; + } + /** * Helper method that allows us to get interpolated values for embedded * animations with a delay and/or different duration. diff --git a/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java index 356a144b7..fa09f237e 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java @@ -26,6 +26,7 @@ import static com.android.quickstep.TouchInteractionService.EDGE_NAV_BAR; import android.graphics.Rect; import android.view.MotionEvent; +import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.anim.SpringAnimationHandler; import com.android.launcher3.dragndrop.DragLayer; @@ -56,11 +57,7 @@ public class EdgeSwipeController extends VerticalSwipeController { @Override protected boolean isTransitionFlipped() { - if (mLauncher.getDeviceProfile().isVerticalBarLayout()) { - Rect insets = mLauncher.getDragLayer().getInsets(); - return insets.left > insets.right; - } - return false; + return mLauncher.getDeviceProfile().isSeascape(); } @Override @@ -82,9 +79,10 @@ public class EdgeSwipeController extends VerticalSwipeController { RecentsView.getPageRect(launcher.getDeviceProfile(), launcher, sTempRect); DragLayer dl = launcher.getDragLayer(); Rect insets = dl.getInsets(); + DeviceProfile dp = launcher.getDeviceProfile(); - if (launcher.getDeviceProfile().isVerticalBarLayout()) { - if (insets.left > insets.right) { + if (dp.isVerticalBarLayout()) { + if (dp.isSeascape()) { return insets.left + sTempRect.left; } else { return dl.getWidth() - sTempRect.right + insets.right; diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java index a004dacde..b4f40c215 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java +++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java @@ -25,7 +25,6 @@ import android.view.View; import android.view.View.AccessibilityDelegate; import com.android.launcher3.Launcher; -import com.android.launcher3.LauncherAppTransitionManager; import com.android.launcher3.LauncherStateManager.StateHandler; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.graphics.BitmapRenderer; @@ -84,31 +83,4 @@ public class UiFactory { RecentsView recents = launcher.getOverviewPanel(); recents.reset(); } - - private static boolean hasControlRemoteAppTransitionPermission(Launcher launcher) { - return launcher.checkSelfPermission(CONTROL_REMOTE_APP_TRANSITION_PERMISSION) - == PackageManager.PERMISSION_GRANTED; - } - - public static Bundle getActivityLaunchOptions(Launcher launcher, View v) { - if (hasControlRemoteAppTransitionPermission(launcher)) { - try { - return new LauncherAppTransitionManager(launcher).getActivityLauncherOptions(v); - } catch (NoClassDefFoundError e) { - // Gracefully fall back to default launch options if the user's platform doesn't - // have the latest changes. - } - } - return launcher.getDefaultActivityLaunchOptions(v); - } - - public static void registerRemoteAnimations(Launcher launcher) { - if (hasControlRemoteAppTransitionPermission(launcher)) { - try { - new LauncherAppTransitionManager(launcher).registerRemoteAnimations(); - } catch (NoClassDefFoundError e) { - // Gracefully fall back if the user's platform doesn't have the latest changes - } - } - } } diff --git a/quickstep/src/com/android/quickstep/RecentsView.java b/quickstep/src/com/android/quickstep/RecentsView.java index 31f8058af..b35d31bfe 100644 --- a/quickstep/src/com/android/quickstep/RecentsView.java +++ b/quickstep/src/com/android/quickstep/RecentsView.java @@ -176,7 +176,7 @@ public class RecentsView extends PagedView implements Insettable { if (dp.isVerticalBarLayout()) { boolean wasScrimOnLeft = mScrimOnLeft; - mScrimOnLeft = insets.left > insets.right; + mScrimOnLeft = dp.isSeascape(); if (mScrim == null || wasScrimOnLeft != mScrimOnLeft) { Drawable scrim = getContext().getDrawable(mScrimOnLeft diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java new file mode 100644 index 000000000..c2fb7beb7 --- /dev/null +++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2018 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.quickstep; + +import android.content.Context; +import android.graphics.Matrix; +import android.view.View; + +import com.android.launcher3.R; +import com.android.launcher3.Utilities; +import com.android.launcher3.util.Preconditions; +import com.android.systemui.shared.recents.model.ThumbnailData; + +/** + * Factory class to create and add an overlays on the TaskView + */ +public class TaskOverlayFactory { + + private static TaskOverlayFactory sInstance; + + public static TaskOverlayFactory get(Context context) { + Preconditions.assertUIThread(); + if (sInstance == null) { + sInstance = Utilities.getOverrideObject(TaskOverlayFactory.class, + context.getApplicationContext(), R.string.task_overlay_factory_class); + } + return sInstance; + } + + public TaskOverlay createOverlay(View thumbnailView) { + return new TaskOverlay(); + } + + public static class TaskOverlay { + + public void setTaskInfo(ThumbnailData thumbnail, Matrix matrix) { } + + public void reset() { } + + } +} diff --git a/quickstep/src/com/android/quickstep/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/TaskThumbnailView.java index 87dec6759..36a0601c8 100644 --- a/quickstep/src/com/android/quickstep/TaskThumbnailView.java +++ b/quickstep/src/com/android/quickstep/TaskThumbnailView.java @@ -28,7 +28,6 @@ import android.graphics.LinearGradient; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PorterDuff.Mode; -import android.graphics.Rect; import android.graphics.Shader; import android.util.AttributeSet; import android.view.View; @@ -36,6 +35,7 @@ import android.view.View; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.R; +import com.android.quickstep.TaskOverlayFactory.TaskOverlay; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.ThumbnailData; @@ -49,15 +49,14 @@ public class TaskThumbnailView extends View { private final float mCornerRadius; private final float mFadeLength; + private final TaskOverlay mOverlay; private final Paint mPaint = new Paint(); private final Matrix mMatrix = new Matrix(); - private final Rect mThumbnailRect = new Rect(); private ThumbnailData mThumbnailData; protected BitmapShader mBitmapShader; - private float mThumbnailScale; private float mDimAlpha = 1f; public TaskThumbnailView(Context context) { @@ -72,6 +71,11 @@ public class TaskThumbnailView extends View { super(context, attrs, defStyleAttr); mCornerRadius = getResources().getDimension(R.dimen.task_corner_radius); mFadeLength = getResources().getDimension(R.dimen.task_fade_length); + mOverlay = TaskOverlayFactory.get(context).createOverlay(this); + } + + public void bind() { + mOverlay.reset(); } /** @@ -83,19 +87,15 @@ public class TaskThumbnailView extends View { if (thumbnailData != null && thumbnailData.thumbnail != null) { Bitmap bm = thumbnailData.thumbnail; bm.prepareToDraw(); - mThumbnailScale = thumbnailData.scale; mBitmapShader = new BitmapShader(bm, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); mPaint.setShader(mBitmapShader); - mThumbnailRect.set(0, 0, - bm.getWidth() - thumbnailData.insets.left - thumbnailData.insets.right, - bm.getHeight() - thumbnailData.insets.top - thumbnailData.insets.bottom); mThumbnailData = thumbnailData; updateThumbnailMatrix(); } else { mBitmapShader = null; mThumbnailData = null; mPaint.setShader(null); - mThumbnailRect.setEmpty(); + mOverlay.reset(); } updateThumbnailPaintFilter(); } @@ -126,36 +126,41 @@ public class TaskThumbnailView extends View { } private void updateThumbnailMatrix() { - mThumbnailScale = 1f; if (mBitmapShader != null && mThumbnailData != null) { + float scale = mThumbnailData.scale; + float thumbnailWidth = mThumbnailData.thumbnail.getWidth() - + (mThumbnailData.insets.left + mThumbnailData.insets.right) * scale; + float thumbnailHeight = mThumbnailData.thumbnail.getHeight() - + (mThumbnailData.insets.top + mThumbnailData.insets.bottom) * scale; + final float thumbnailScale; + if (getMeasuredWidth() == 0) { // If we haven't measured , skip the thumbnail drawing and only draw the background // color - mThumbnailScale = 0f; + thumbnailScale = 0f; } else { - float invThumbnailScale = 1f / mThumbnailScale; final Configuration configuration = getContext().getApplicationContext().getResources().getConfiguration(); final DeviceProfile profile = Launcher.getLauncher(getContext()).getDeviceProfile(); if (configuration.orientation == mThumbnailData.orientation) { // If we are in the same orientation as the screenshot, just scale it to the // width of the task view - mThumbnailScale = (float) getMeasuredWidth() / mThumbnailRect.width(); + thumbnailScale = getMeasuredWidth() / thumbnailWidth; } else if (configuration.orientation == Configuration.ORIENTATION_PORTRAIT) { // Scale the landscape thumbnail up to app size, then scale that to the task // view size to match other portrait screenshots - mThumbnailScale = invThumbnailScale * - ((float) getMeasuredWidth() / profile.widthPx); + thumbnailScale = ((float) getMeasuredWidth() / profile.widthPx); } else { // Otherwise, scale the screenshot to fit 1:1 in the current orientation - mThumbnailScale = invThumbnailScale; + thumbnailScale = 1; } } - mMatrix.setTranslate(-mThumbnailData.insets.left, -mThumbnailData.insets.top); - mMatrix.postScale(mThumbnailScale, mThumbnailScale); + mMatrix.setTranslate(-mThumbnailData.insets.left * scale, + -mThumbnailData.insets.top * scale); + mMatrix.postScale(thumbnailScale, thumbnailScale); mBitmapShader.setLocalMatrix(mMatrix); - float bitmapHeight = Math.max(mThumbnailRect.height() * mThumbnailScale, 0); + float bitmapHeight = Math.max(thumbnailHeight * thumbnailScale, 0); Shader shader = mBitmapShader; if (bitmapHeight < getMeasuredHeight()) { int color = mPaint.getColor(); @@ -165,7 +170,7 @@ public class TaskThumbnailView extends View { shader = new ComposeShader(fade, shader, Mode.DST_OVER); } - float bitmapWidth = Math.max(mThumbnailRect.width() * mThumbnailScale, 0); + float bitmapWidth = Math.max(thumbnailWidth * thumbnailScale, 0); if (bitmapWidth < getMeasuredWidth()) { int color = mPaint.getColor(); LinearGradient fade = new LinearGradient( @@ -175,6 +180,8 @@ public class TaskThumbnailView extends View { } mPaint.setShader(shader); } + + mOverlay.setTaskInfo(mThumbnailData, mMatrix); invalidate(); } diff --git a/quickstep/src/com/android/quickstep/TaskView.java b/quickstep/src/com/android/quickstep/TaskView.java index 0e999f8e3..46fcc724c 100644 --- a/quickstep/src/com/android/quickstep/TaskView.java +++ b/quickstep/src/com/android/quickstep/TaskView.java @@ -36,6 +36,7 @@ import android.widget.ImageView; import com.android.launcher3.R; import com.android.quickstep.RecentsView.PageCallbacks; import com.android.quickstep.RecentsView.ScrollState; +import com.android.quickstep.TaskOverlayFactory.TaskOverlay; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.Task.TaskCallbacks; import com.android.systemui.shared.recents.model.ThumbnailData; @@ -113,6 +114,7 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback mTask.removeCallback(this); } mTask = task; + mSnapshotView.bind(); task.addCallback(this); } diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java index fe187038c..509ffa9dc 100644 --- a/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -185,6 +185,7 @@ public class TouchInteractionService extends Service { @Override public void onDestroy() { sConnected = false; + sQuickScrubEnabled = false; super.onDestroy(); } diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml index 8cf32bd0e..2ce6b8cfd 100644 --- a/res/layout/all_apps.xml +++ b/res/layout/all_apps.xml @@ -31,48 +31,7 @@ <include layout="@layout/all_apps_fast_scroller" /> - <com.android.launcher3.allapps.FloatingHeaderView - android:id="@+id/all_apps_header" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:paddingTop="@dimen/all_apps_header_top_padding" - android:clipToPadding="false" - android:layout_below="@id/search_container_all_apps" > - - <include layout="@layout/predictions_view" android:id="@+id/header_content" /> - - <com.android.launcher3.allapps.PersonalWorkSlidingTabStrip - android:id="@+id/tabs" - android:layout_width="match_parent" - android:layout_height="@dimen/all_apps_header_tab_height" - android:layout_marginLeft="@dimen/all_apps_tabs_side_padding" - android:layout_marginRight="@dimen/all_apps_tabs_side_padding" - android:layout_below="@id/header_content" - android:orientation="horizontal"> - <Button - android:id="@+id/tab_personal" - android:layout_width="0dp" - android:layout_height="match_parent" - android:layout_weight="1" - android:background="?android:attr/selectableItemBackground" - android:fontFamily="sans-serif-medium" - android:text="@string/all_apps_personal_tab" - android:textAllCaps="true" - android:textColor="@color/all_apps_tab_text" - android:textSize="14sp"/> - <Button - android:id="@+id/tab_work" - android:layout_width="0dp" - android:layout_height="match_parent" - android:layout_weight="1" - android:background="?android:attr/selectableItemBackground" - android:fontFamily="sans-serif-medium" - android:text="@string/all_apps_work_tab" - android:textAllCaps="true" - android:textColor="@color/all_apps_work_tab_text" - android:textSize="14sp"/> - </com.android.launcher3.allapps.PersonalWorkSlidingTabStrip> - </com.android.launcher3.allapps.FloatingHeaderView> + <include layout="@layout/all_apps_floating_header" /> <!-- Note: we are reusing/repurposing a system attribute for search layout, because of a platform bug, which prevents using custom attributes in <include> tag --> diff --git a/res/layout/all_apps_floating_header.xml b/res/layout/all_apps_floating_header.xml new file mode 100644 index 000000000..166725da3 --- /dev/null +++ b/res/layout/all_apps_floating_header.xml @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2018 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. +--> +<com.android.launcher3.allapps.FloatingHeaderView + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/all_apps_header" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/search_container_all_apps" + android:clipToPadding="false" + android:paddingTop="@dimen/all_apps_header_top_padding" + android:orientation="vertical" > + + <com.android.launcher3.allapps.PersonalWorkSlidingTabStrip + android:id="@+id/tabs" + android:layout_width="match_parent" + android:layout_height="@dimen/all_apps_header_tab_height" + android:layout_marginLeft="@dimen/all_apps_tabs_side_padding" + android:layout_marginRight="@dimen/all_apps_tabs_side_padding" + android:orientation="horizontal"> + + <Button + android:id="@+id/tab_personal" + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:background="?android:attr/selectableItemBackground" + android:fontFamily="sans-serif-medium" + android:text="@string/all_apps_personal_tab" + android:textAllCaps="true" + android:textColor="@color/all_apps_tab_text" + android:textSize="14sp" /> + + <Button + android:id="@+id/tab_work" + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:background="?android:attr/selectableItemBackground" + android:fontFamily="sans-serif-medium" + android:text="@string/all_apps_work_tab" + android:textAllCaps="true" + android:textColor="@color/all_apps_work_tab_text" + android:textSize="14sp" /> + </com.android.launcher3.allapps.PersonalWorkSlidingTabStrip> +</com.android.launcher3.allapps.FloatingHeaderView> diff --git a/res/values/config.xml b/res/values/config.xml index 209620038..3dddac22d 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -92,6 +92,9 @@ <!-- Name of a user event dispatcher class. --> <string name="user_event_dispatcher_class" translatable="false"></string> + <!-- Name of an app transition manager class. --> + <string name="app_transition_manager_class" translatable="false"></string> + <!-- Name of a color extraction implementation class. --> <string name="color_extraction_impl_class" translatable="false"></string> diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index 164efe54a..5789755ca 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -412,7 +412,7 @@ public class DeviceProfile { padding.bottom = edgeMarginPx; padding.left = hotseatBarSidePaddingPx; padding.right = hotseatBarSidePaddingPx; - if (mInsets.left > mInsets.right) { + if (isSeascape()) { padding.left += hotseatBarSizePx; padding.right += pageIndicatorSizePx; } else { @@ -480,6 +480,11 @@ public class DeviceProfile { return isLandscape && transposeLayoutWithOrientation; } + public boolean isSeascape() { + // TODO: This might not hold true for multi window mode, use configuration insead. + return isVerticalBarLayout() && mInsets.left > mInsets.right; + } + public boolean shouldFadeAdjacentWorkspaceScreens() { return isVerticalBarLayout() || isLargeTablet; } diff --git a/src/com/android/launcher3/DropTargetBar.java b/src/com/android/launcher3/DropTargetBar.java index d78043d88..cc6a58f9a 100644 --- a/src/com/android/launcher3/DropTargetBar.java +++ b/src/com/android/launcher3/DropTargetBar.java @@ -93,8 +93,8 @@ public class DropTargetBar extends FrameLayout if (grid.isVerticalBarLayout()) { lp.width = grid.dropTargetBarSizePx; lp.height = grid.availableHeightPx - 2 * grid.edgeMarginPx; - lp.gravity = insets.left > insets.right ? Gravity.RIGHT : Gravity.LEFT; - tooltipLocation = insets.left > insets.right ? TOOLTIP_LEFT : TOOLTIP_RIGHT; + lp.gravity = grid.isSeascape() ? Gravity.RIGHT : Gravity.LEFT; + tooltipLocation = grid.isSeascape() ? TOOLTIP_LEFT : TOOLTIP_RIGHT; } else { int gap; if (grid.isTablet) { diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java index 25eacb52f..9d2bb070e 100644 --- a/src/com/android/launcher3/Hotseat.java +++ b/src/com/android/launcher3/Hotseat.java @@ -164,7 +164,7 @@ public class Hotseat extends FrameLayout implements LogContainerProvider, Insett mContent.setGridSize(1, grid.inv.numHotseatIcons); lp.height = ViewGroup.LayoutParams.MATCH_PARENT; - if (insets.left > insets.right) { + if (grid.isSeascape()) { lp.gravity = Gravity.LEFT; lp.width = grid.hotseatBarSizePx + insets.left + grid.hotseatBarSidePaddingPx; getLayout().setPadding( diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java index a5ca3eece..957a5e51f 100644 --- a/src/com/android/launcher3/IconCache.java +++ b/src/com/android/launcher3/IconCache.java @@ -118,8 +118,7 @@ public class IconCache { mIconDpi = inv.fillResIconDpi; mIconDb = new IconDB(context, inv.iconBitmapSize); - mIconProvider = Utilities.getOverrideObject( - IconProvider.class, context, R.string.icon_provider_class); + mIconProvider = IconProvider.newInstance(context); mWorkerHandler = new Handler(LauncherModel.getWorkerLooper()); mLowResOptions = new BitmapFactory.Options(); @@ -254,7 +253,7 @@ public class IconCache { // Remove all active icon update tasks. mWorkerHandler.removeCallbacksAndMessages(ICON_UPDATE_TOKEN); - mIconProvider.updateSystemStateString(); + mIconProvider.updateSystemStateString(mContext); for (UserHandle user : mUserManager.getUserProfiles()) { // Query for the set of apps final List<LauncherActivityInfo> apps = mLauncherApps.getActivityList(null, user); diff --git a/src/com/android/launcher3/IconProvider.java b/src/com/android/launcher3/IconProvider.java index 4dee2b57d..b469a8f45 100644 --- a/src/com/android/launcher3/IconProvider.java +++ b/src/com/android/launcher3/IconProvider.java @@ -1,5 +1,6 @@ package com.android.launcher3; +import android.content.Context; import android.content.pm.LauncherActivityInfo; import android.graphics.drawable.Drawable; import android.os.Build; @@ -8,17 +9,26 @@ import java.util.Locale; public class IconProvider { - private static final boolean DBG = false; - private static final String TAG = "IconProvider"; - protected String mSystemState; - public IconProvider() { - updateSystemStateString(); + public static IconProvider newInstance(Context context) { + IconProvider provider = Utilities.getOverrideObject( + IconProvider.class, context, R.string.icon_provider_class); + provider.updateSystemStateString(context); + return provider; } - public void updateSystemStateString() { - mSystemState = Locale.getDefault().toString() + "," + Build.VERSION.SDK_INT; + public IconProvider() { } + + public void updateSystemStateString(Context context) { + final String locale; + if (Utilities.ATLEAST_NOUGAT) { + locale = context.getResources().getConfiguration().getLocales().toLanguageTags(); + } else { + locale = Locale.getDefault().toString(); + } + + mSystemState = locale + "," + Build.VERSION.SDK_INT; } public String getIconSystemState(String packageName) { diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 5db0a3b72..a91907d44 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -214,6 +214,8 @@ public class Launcher extends BaseActivity private static final int NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS = 5; @Thunk static final int NEW_APPS_ANIMATION_DELAY = 500; + private LauncherAppTransitionManager mAppTransitionManager; + @Thunk Workspace mWorkspace; private View mLauncherView; @Thunk DragLayer mDragLayer; @@ -403,8 +405,11 @@ public class Launcher extends BaseActivity getSystemUiController().updateUiState(SystemUiController.UI_STATE_BASE_WINDOW, Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText)); + mAppTransitionManager = Utilities.getOverrideObject(LauncherAppTransitionManager.class, + this, R.string.app_transition_manager_class); + if (!isInMultiWindowModeCompat()) { - UiFactory.registerRemoteAnimations(this); + mAppTransitionManager.registerRemoteAnimations(); } if (mLauncherCallbacks != null) { @@ -1918,38 +1923,11 @@ public class Launcher extends BaseActivity } } - public Bundle getDefaultActivityLaunchOptions(View v) { - if (Utilities.ATLEAST_MARSHMALLOW) { - int left = 0, top = 0; - int width = v.getMeasuredWidth(), height = v.getMeasuredHeight(); - if (v instanceof BubbleTextView) { - // Launch from center of icon, not entire view - Drawable icon = ((BubbleTextView) v).getIcon(); - if (icon != null) { - Rect bounds = icon.getBounds(); - left = (width - bounds.width()) / 2; - top = v.getPaddingTop(); - width = bounds.width(); - height = bounds.height(); - } - } - return ActivityOptions.makeClipRevealAnimation(v, left, top, width, height) - .toBundle(); - } else if (Utilities.ATLEAST_LOLLIPOP_MR1) { - // On L devices, we use the device default slide-up transition. - // On L MR1 devices, we use a custom version of the slide-up transition which - // doesn't have the delay present in the device default. - return ActivityOptions.makeCustomAnimation( - this, R.anim.task_open_enter, R.anim.no_anim).toBundle(); - } - return null; - } - @TargetApi(Build.VERSION_CODES.M) public Bundle getActivityLaunchOptions(View v, boolean useDefaultLaunchOptions) { return useDefaultLaunchOptions - ? getDefaultActivityLaunchOptions(v) - : UiFactory.getActivityLaunchOptions(this, v); + ? mAppTransitionManager.getDefaultActivityLaunchOptions(this, v) + : mAppTransitionManager.getActivityLaunchOptions(this, v); } public Rect getViewBounds(View v) { diff --git a/src/com/android/launcher3/LauncherAppTransitionManager.java b/src/com/android/launcher3/LauncherAppTransitionManager.java new file mode 100644 index 000000000..9d68dc9e8 --- /dev/null +++ b/src/com/android/launcher3/LauncherAppTransitionManager.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2018 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.launcher3; + + +import android.app.ActivityOptions; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.view.View; + +/** + * Manages the opening and closing app transitions from Launcher. + */ +public class LauncherAppTransitionManager { + + public Bundle getDefaultActivityLaunchOptions(Launcher launcher, View v) { + if (Utilities.ATLEAST_MARSHMALLOW) { + int left = 0, top = 0; + int width = v.getMeasuredWidth(), height = v.getMeasuredHeight(); + if (v instanceof BubbleTextView) { + // Launch from center of icon, not entire view + Drawable icon = ((BubbleTextView) v).getIcon(); + if (icon != null) { + Rect bounds = icon.getBounds(); + left = (width - bounds.width()) / 2; + top = v.getPaddingTop(); + width = bounds.width(); + height = bounds.height(); + } + } + return ActivityOptions.makeClipRevealAnimation(v, left, top, width, height) + .toBundle(); + } else if (Utilities.ATLEAST_LOLLIPOP_MR1) { + // On L devices, we use the device default slide-up transition. + // On L MR1 devices, we use a custom version of the slide-up transition which + // doesn't have the delay present in the device default. + return ActivityOptions.makeCustomAnimation(launcher, R.anim.task_open_enter, + R.anim.no_anim).toBundle(); + } + return null; + } + + public Bundle getActivityLaunchOptions(Launcher launcher, View v) { + return getDefaultActivityLaunchOptions(launcher, v); + } + + public void registerRemoteAnimations() { + } +} diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java index 2e544ecef..dc3de18d5 100644 --- a/src/com/android/launcher3/allapps/AllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java @@ -55,13 +55,11 @@ import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.keyboard.FocusedItemDecorator; import com.android.launcher3.userevent.nano.LauncherLogProto.Target; -import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.ComponentKeyMapper; import com.android.launcher3.util.ItemInfoMatcher; import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.views.BottomUserEducationView; -import java.util.HashMap; import java.util.List; import java.util.Set; @@ -76,6 +74,7 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource, private final ClickShadowView mTouchFeedbackView; private final ItemInfoMatcher mPersonalMatcher = ItemInfoMatcher.ofUser(Process.myUserHandle()); private final ItemInfoMatcher mWorkMatcher = ItemInfoMatcher.not(mPersonalMatcher); + private final AllAppsStore mAllAppsStore = new AllAppsStore(); private SearchUiManager mSearchUiManager; private View mSearchContainer; @@ -92,8 +91,6 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource, private boolean mHasPredictions = false; private boolean mSearchModeWhileUsingTabs = false; - private final HashMap<ComponentKey, AppInfo> mComponentToAppMap = new HashMap<>(); - public AllAppsContainerView(Context context) { this(context, null); } @@ -132,6 +129,10 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource, // TODO: Reimplement once fast scroller is fixed. } + public AllAppsStore getAppsStore() { + return mAllAppsStore; + } + @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); @@ -149,64 +150,29 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource, public void setApps(List<AppInfo> apps) { boolean hasWorkProfileApp = hasWorkProfileApp(apps); rebindAdapters(hasWorkProfileApp); - mComponentToAppMap.clear(); - addOrUpdateApps(apps); + mAllAppsStore.setApps(apps); } /** * Adds or updates existing apps in the list */ public void addOrUpdateApps(List<AppInfo> apps) { - for (AppInfo app : apps) { - mComponentToAppMap.put(app.toComponentKey(), app); - } - onAppsUpdated(); - mSearchUiManager.refreshSearchResult(); - mHeader.onAppsUpdated(); + mAllAppsStore.addOrUpdateApps(apps); } /** * Removes some apps from the list. */ public void removeApps(List<AppInfo> apps) { - for (AppInfo app : apps) { - mComponentToAppMap.remove(app.toComponentKey()); - } - onAppsUpdated(); - mSearchUiManager.refreshSearchResult(); - } - - private void onAppsUpdated() { - for (int i = 0; i < getNumOfAdapters(); i++) { - mAH[i].appsList.onAppsUpdated(); - } - } - - private int getNumOfAdapters() { - return mUsingTabs ? mAH.length : 1; + mAllAppsStore.removeApps(apps); } public void updatePromiseAppProgress(PromiseAppInfo app) { - for (int i = 0; i < mAH.length; i++) { - updatePromiseAppProgress(app, mAH[i].recyclerView); - } - if (isHeaderVisible()) { - updatePromiseAppProgress(app, mHeader.getPredictionRow()); - } - } - - private void updatePromiseAppProgress(PromiseAppInfo app, ViewGroup parent) { - if (parent == null) { - return; - } - int childCount = parent.getChildCount(); - for (int i = 0; i < childCount; i++) { - View child = parent.getChildAt(i); - if (child instanceof BubbleTextView && child.getTag() == app) { - BubbleTextView bubbleTextView = (BubbleTextView) child; - bubbleTextView.applyProgressLevel(app.level); + mAllAppsStore.updateAllIcons((child) -> { + if (child.getTag() == app) { + child.applyProgressLevel(app.level); } - } + }); } /** @@ -358,34 +324,15 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource, } public void updateIconBadges(Set<PackageUserKey> updatedBadges) { - final PackageUserKey packageUserKey = new PackageUserKey(null, null); - for (int j = 0; j < mAH.length; j++) { - updateIconBadges(updatedBadges, packageUserKey, mAH[j].recyclerView); - } - if (mHeader != null) { - updateIconBadges(updatedBadges, packageUserKey, mHeader.getPredictionRow()); - } - } - - private void updateIconBadges(Set<PackageUserKey> updatedBadges, PackageUserKey packageUserKey, - ViewGroup parent) { - if (parent == null) { - return; - } - final int n = parent.getChildCount(); - for (int i = 0; i < n; i++) { - View child = parent.getChildAt(i); - if (child instanceof PredictionRowView) { - updateIconBadges(updatedBadges, packageUserKey, (PredictionRowView) child); - } - if (!(child instanceof BubbleTextView) || !(child.getTag() instanceof ItemInfo)) { - continue; - } - ItemInfo info = (ItemInfo) child.getTag(); - if (packageUserKey.updateFromItemInfo(info) && updatedBadges.contains(packageUserKey)) { - ((BubbleTextView) child).applyBadgeState(info, true /* animate */); + PackageUserKey tempKey = new PackageUserKey(null, null); + mAllAppsStore.updateAllIcons((child) -> { + if (child.getTag() instanceof ItemInfo) { + ItemInfo info = (ItemInfo) child.getTag(); + if (tempKey.updateFromItemInfo(info) && updatedBadges.contains(tempKey)) { + child.applyBadgeState(info, true /* animate */); + } } - } + }); } public SpringAnimationHandler getSpringAnimationHandler() { @@ -403,6 +350,9 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource, replaceRVContainer(showTabs); mUsingTabs = showTabs; + mAllAppsStore.unregisterIconContainer(mAH[AdapterHolder.MAIN].recyclerView); + mAllAppsStore.unregisterIconContainer(mAH[AdapterHolder.WORK].recyclerView); + if (mUsingTabs) { mAH[AdapterHolder.MAIN].setup(mViewPager.getChildAt(0), mPersonalMatcher); mAH[AdapterHolder.WORK].setup(mViewPager.getChildAt(1), mWorkMatcher); @@ -419,6 +369,9 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource, } } + mAllAppsStore.registerIconContainer(mAH[AdapterHolder.MAIN].recyclerView); + mAllAppsStore.registerIconContainer(mAH[AdapterHolder.WORK].recyclerView); + applyTouchDelegate(); } @@ -492,9 +445,6 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource, } public void setPredictedApps(List<ComponentKeyMapper<AppInfo>> apps) { - if (isHeaderVisible()) { - mHeader.getPredictionRow().setPredictedApps(apps); - } mAH[AdapterHolder.MAIN].appsList.setPredictedApps(apps); boolean hasPredictions = !apps.isEmpty(); if (mHasPredictions != hasPredictions) { @@ -506,7 +456,7 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource, } public AppInfo findApp(ComponentKeyMapper<AppInfo> mapper) { - return mapper.getItem(mComponentToAppMap); + return mAllAppsStore.getApp(mapper); } public AlphabeticalAppsList getApps() { @@ -526,9 +476,9 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource, return; } mHeader.setVisibility(View.VISIBLE); - mHeader.setup(mAH, mComponentToAppMap, mNumPredictedAppsPerRow); + mHeader.setup(mAH, mAH[AllAppsContainerView.AdapterHolder.WORK].recyclerView == null); - int padding = mHeader.getPredictionRow().getExpectedHeight(); + int padding = mHeader.getMaxTranslation(); if (mHasPredictions && !mUsingTabs) { padding += mHeader.getPaddingTop() + mHeader.getPaddingBottom(); } @@ -582,14 +532,6 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource, } } - public List<AppInfo> getPredictedApps() { - if (isHeaderVisible()) { - return mHeader.getPredictionRow().getPredictedApps(); - } else { - return mAH[AdapterHolder.MAIN].appsList.getPredictedApps(); - } - } - public boolean isHeaderVisible() { return mHeader != null && mHeader.getVisibility() == View.VISIBLE; } @@ -604,7 +546,7 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource, public static final int MAIN = 0; public static final int WORK = 1; - final AllAppsGridAdapter adapter; + public final AllAppsGridAdapter adapter; final LinearLayoutManager layoutManager; final SpringAnimationHandler animationHandler; final AlphabeticalAppsList appsList; @@ -614,7 +556,7 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource, boolean verticalFadingEdge; AdapterHolder(boolean isWork) { - appsList = new AlphabeticalAppsList(mLauncher, mComponentToAppMap, isWork); + appsList = new AlphabeticalAppsList(mLauncher, mAllAppsStore, isWork); adapter = new AllAppsGridAdapter(mLauncher, appsList, mLauncher, AllAppsContainerView.this, true); appsList.setAdapter(adapter); @@ -649,11 +591,6 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource, ? paddingTopForTabs : padding.top; recyclerView.setPadding(padding.left, paddingTop, padding.right, padding.bottom); } - if (isHeaderVisible()) { - PredictionRowView prv = mHeader.getPredictionRow(); - prv.setPadding(padding.left, prv.getPaddingTop() , padding.right, - prv.getPaddingBottom()); - } } void applyNumsPerRow() { @@ -663,10 +600,6 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource, } adapter.setNumAppsPerRow(mNumAppsPerRow); appsList.setNumAppsPerRow(mNumAppsPerRow, mNumPredictedAppsPerRow); - if (isHeaderVisible()) { - mHeader.getPredictionRow() - .setNumAppsPerRow(mNumPredictedAppsPerRow); - } } } diff --git a/src/com/android/launcher3/allapps/AllAppsStore.java b/src/com/android/launcher3/allapps/AllAppsStore.java new file mode 100644 index 000000000..17f1c8910 --- /dev/null +++ b/src/com/android/launcher3/allapps/AllAppsStore.java @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2018 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.launcher3.allapps; + +import android.view.View; +import android.view.ViewGroup; + +import com.android.launcher3.AppInfo; +import com.android.launcher3.BubbleTextView; +import com.android.launcher3.util.ComponentKey; +import com.android.launcher3.util.ComponentKeyMapper; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; + +/** + * A utility class to maintain the collection of all apps. + */ +public class AllAppsStore { + + private final HashMap<ComponentKey, AppInfo> mComponentToAppMap = new HashMap<>(); + private final List<OnUpdateListener> mUpdateListeners = new ArrayList<>(); + private final ArrayList<ViewGroup> mIconContainers = new ArrayList<>(); + + public Collection<AppInfo> getApps() { + return mComponentToAppMap.values(); + } + + /** + * Sets the current set of apps. + */ + public void setApps(List<AppInfo> apps) { + mComponentToAppMap.clear(); + addOrUpdateApps(apps); + } + + public AppInfo getApp(ComponentKey key) { + return mComponentToAppMap.get(key); + } + + public AppInfo getApp(ComponentKeyMapper<AppInfo> mapper) { + return mapper.getItem(mComponentToAppMap); + } + + /** + * Adds or updates existing apps in the list + */ + public void addOrUpdateApps(List<AppInfo> apps) { + for (AppInfo app : apps) { + mComponentToAppMap.put(app.toComponentKey(), app); + } + notifyUpdate(); + } + + /** + * Removes some apps from the list. + */ + public void removeApps(List<AppInfo> apps) { + for (AppInfo app : apps) { + mComponentToAppMap.remove(app.toComponentKey()); + } + notifyUpdate(); + } + + + private void notifyUpdate() { + int count = mUpdateListeners.size(); + for (int i = 0; i < count; i++) { + mUpdateListeners.get(i).onAppsUpdated(); + } + } + + public void addUpdateListener(OnUpdateListener listener) { + mUpdateListeners.add(listener); + } + + public void removeUpdateListener(OnUpdateListener listener) { + mUpdateListeners.remove(listener); + } + + public void registerIconContainer(ViewGroup container) { + if (container != null) { + mIconContainers.add(container); + } + } + + public void unregisterIconContainer(ViewGroup container) { + mIconContainers.remove(container); + } + + public void updateAllIcons(IconAction action) { + for (int i = mIconContainers.size() - 1; i >= 0; i--) { + ViewGroup parent = mIconContainers.get(i); + int childCount = parent.getChildCount(); + + for (int j = 0; j < childCount; j++) { + View child = parent.getChildAt(j); + if (child instanceof BubbleTextView) { + action.apply((BubbleTextView) child); + } + } + } + } + + public interface OnUpdateListener { + void onAppsUpdated(); + } + + public interface IconAction { + void apply(BubbleTextView icon); + } +} diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java index 76828deb6..29b32b06c 100644 --- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java +++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java @@ -44,7 +44,7 @@ import java.util.TreeMap; /** * The alphabetically sorted list of applications. */ -public class AlphabeticalAppsList { +public class AlphabeticalAppsList implements AllAppsStore.OnUpdateListener { public static final String TAG = "AlphabeticalAppsList"; private static final boolean DEBUG = false; @@ -153,7 +153,7 @@ public class AlphabeticalAppsList { // The set of apps from the system not including predictions private final List<AppInfo> mApps = new ArrayList<>(); - private final HashMap<ComponentKey, AppInfo> mComponentToAppMap; + private final AllAppsStore mAllAppsStore; // The set of filtered apps with the current filter private final List<AppInfo> mFilteredApps = new ArrayList<>(); @@ -179,16 +179,13 @@ public class AlphabeticalAppsList { private int mNumAppRowsInAdapter; private ItemInfoMatcher mItemFilter; - public AlphabeticalAppsList( - Context context, - HashMap<ComponentKey, - AppInfo> componentToAppMap, - boolean isWork) { - mComponentToAppMap = componentToAppMap; + public AlphabeticalAppsList(Context context, AllAppsStore appsStore, boolean isWork) { + mAllAppsStore = appsStore; mLauncher = Launcher.getLauncher(context); mIndexer = new AlphabeticIndexCompat(context); mAppNameComparator = new AppInfoComparator(context); mIsWork = isWork; + mAllAppsStore.addUpdateListener(this); } public void updateItemFilter(ItemInfoMatcher itemFilter) { @@ -283,14 +280,14 @@ public class AlphabeticalAppsList { } private List<AppInfo> processPredictedAppComponents(List<ComponentKeyMapper<AppInfo>> components) { - if (mComponentToAppMap.isEmpty()) { + if (mAllAppsStore.getApps().isEmpty()) { // Apps have not been bound yet. return Collections.emptyList(); } List<AppInfo> predictedApps = new ArrayList<>(); for (ComponentKeyMapper<AppInfo> mapper : components) { - AppInfo info = mapper.getItem(mComponentToAppMap); + AppInfo info = mAllAppsStore.getApp(mapper); if (info != null) { predictedApps.add(info); } else { @@ -359,11 +356,12 @@ public class AlphabeticalAppsList { /** * Updates internals when the set of apps are updated. */ - void onAppsUpdated() { + @Override + public void onAppsUpdated() { // Sort the list of apps mApps.clear(); - for (AppInfo app : mComponentToAppMap.values()) { + for (AppInfo app : mAllAppsStore.getApps()) { if (mItemFilter == null || mItemFilter.matches(app, null) || hasFilter()) { mApps.add(app); } @@ -580,7 +578,7 @@ public class AlphabeticalAppsList { } ArrayList<AppInfo> result = new ArrayList<>(); for (ComponentKey key : mSearchResults) { - AppInfo match = mComponentToAppMap.get(key); + AppInfo match = mAllAppsStore.getApp(key); if (match != null) { result.add(match); } diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java index 23917683f..d8a9f6364 100644 --- a/src/com/android/launcher3/allapps/FloatingHeaderView.java +++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java @@ -15,7 +15,6 @@ */ package com.android.launcher3.allapps; - import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Point; @@ -27,18 +26,14 @@ import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; +import android.widget.LinearLayout; import android.widget.RelativeLayout; -import com.android.launcher3.AppInfo; import com.android.launcher3.R; -import com.android.launcher3.util.ComponentKey; - -import java.util.HashMap; -public class FloatingHeaderView extends RelativeLayout implements +public class FloatingHeaderView extends LinearLayout implements ValueAnimator.AnimatorUpdateListener { - private final Rect mClip = new Rect(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE); private final ValueAnimator mAnimator = ValueAnimator.ofInt(0, 0); private final Point mTempOffset = new Point(); @@ -63,19 +58,18 @@ public class FloatingHeaderView extends RelativeLayout implements } }; - private PredictionRowView mPredictionRow; private ViewGroup mTabLayout; private AllAppsRecyclerView mMainRV; private AllAppsRecyclerView mWorkRV; private AllAppsRecyclerView mCurrentRV; private ViewGroup mParent; - private boolean mTabsHidden; private boolean mHeaderCollapsed; - private int mMaxTranslation; private int mSnappedScrolledY; private int mTranslationY; private boolean mForwardToRecyclerView; + protected int mMaxTranslation; + public FloatingHeaderView(@NonNull Context context) { this(context, null); } @@ -88,17 +82,10 @@ public class FloatingHeaderView extends RelativeLayout implements protected void onFinishInflate() { super.onFinishInflate(); mTabLayout = findViewById(R.id.tabs); - mPredictionRow = findViewById(R.id.header_content); } - public void setup(AllAppsContainerView.AdapterHolder[] mAH, - HashMap<ComponentKey, AppInfo> componentToAppMap, int numPredictedAppsPerRow) { - mTabsHidden = mAH[AllAppsContainerView.AdapterHolder.WORK].recyclerView == null; - mTabLayout.setVisibility(mTabsHidden ? View.GONE : View.VISIBLE); - mPredictionRow.setup(mAH[AllAppsContainerView.AdapterHolder.MAIN].adapter, - componentToAppMap, numPredictedAppsPerRow); - mPredictionRow.setShowDivider(mTabsHidden); - mMaxTranslation = mPredictionRow.getExpectedHeight(); + public void setup(AllAppsContainerView.AdapterHolder[] mAH, boolean tabsHidden) { + mTabLayout.setVisibility(tabsHidden ? View.GONE : View.VISIBLE); mMainRV = setupRV(mMainRV, mAH[AllAppsContainerView.AdapterHolder.MAIN].recyclerView); mWorkRV = setupRV(mWorkRV, mAH[AllAppsContainerView.AdapterHolder.WORK].recyclerView); mParent = (ViewGroup) mMainRV.getParent(); @@ -117,12 +104,12 @@ public class FloatingHeaderView extends RelativeLayout implements mCurrentRV = active ? mMainRV : mWorkRV; } - public PredictionRowView getPredictionRow() { - return mPredictionRow; + public int getMaxTranslation() { + return mMaxTranslation; } private boolean canSnapAt(int currentScrollY) { - return Math.abs(currentScrollY) <= mPredictionRow.getHeight(); + return Math.abs(currentScrollY) <= mMaxTranslation; } private void moved(final int currentScrollY) { @@ -149,16 +136,12 @@ public class FloatingHeaderView extends RelativeLayout implements } } - private void apply() { + protected void applyScroll(int uncappedY, int currentY) { } + + protected void apply() { int uncappedTranslationY = mTranslationY; mTranslationY = Math.max(mTranslationY, -mMaxTranslation); - if (mTranslationY != uncappedTranslationY) { - // we hide it completely if already capped (for opening search anim) - mPredictionRow.setVisibility(View.INVISIBLE); - } else { - mPredictionRow.setVisibility(View.VISIBLE); - mPredictionRow.setTranslationY(uncappedTranslationY); - } + applyScroll(uncappedTranslationY, mTranslationY); mTabLayout.setTranslationY(mTranslationY); mClip.top = mMaxTranslation + mTranslationY; // clipping on a draw might cause additional redraw @@ -218,10 +201,6 @@ public class FloatingHeaderView extends RelativeLayout implements p.x = getLeft() - mCurrentRV.getLeft() - mParent.getLeft(); p.y = getTop() - mCurrentRV.getTop() - mParent.getTop(); } - - public void onAppsUpdated() { - mPredictionRow.onAppsUpdated(); - } } diff --git a/src/com/android/launcher3/allapps/PredictionRowView.java b/src/com/android/launcher3/allapps/PredictionRowView.java deleted file mode 100644 index 267ef3c4f..000000000 --- a/src/com/android/launcher3/allapps/PredictionRowView.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright (C) 2017 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.launcher3.allapps; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.util.AttributeSet; -import android.util.Log; -import android.view.View; -import android.widget.LinearLayout; - -import com.android.launcher3.AppInfo; -import com.android.launcher3.BubbleTextView; -import com.android.launcher3.ItemInfo; -import com.android.launcher3.Launcher; -import com.android.launcher3.R; -import com.android.launcher3.config.FeatureFlags; -import com.android.launcher3.logging.UserEventDispatcher; -import com.android.launcher3.userevent.nano.LauncherLogProto; -import com.android.launcher3.util.ComponentKey; -import com.android.launcher3.util.ComponentKeyMapper; -import com.android.launcher3.util.Themes; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; - -public class PredictionRowView extends LinearLayout implements - UserEventDispatcher.LogContainerProvider { - - private static final String TAG = "PredictionRowView"; - - private HashMap<ComponentKey, AppInfo> mComponentToAppMap; - private int mNumPredictedAppsPerRow; - // The set of predicted app component names - private final List<ComponentKeyMapper<AppInfo>> mPredictedAppComponents = new ArrayList<>(); - // The set of predicted apps resolved from the component names and the current set of apps - private final ArrayList<AppInfo> mPredictedApps = new ArrayList<>(); - private final Paint mPaint; - // This adapter is only used to create an identical item w/ same behavior as in the all apps RV - private AllAppsGridAdapter mAdapter; - private boolean mShowDivider; - - public PredictionRowView(@NonNull Context context) { - this(context, null); - } - - public PredictionRowView(@NonNull Context context, @Nullable AttributeSet attrs) { - super(context, attrs); - setOrientation(LinearLayout.HORIZONTAL); - setWillNotDraw(false); - mPaint = new Paint(); - mPaint.setColor(Themes.getAttrColor(context, android.R.attr.colorControlHighlight)); - mPaint.setStrokeWidth(getResources().getDimensionPixelSize(R.dimen.all_apps_divider_height)); - } - - public void setup(AllAppsGridAdapter adapter, HashMap<ComponentKey, AppInfo> componentToAppMap, - int numPredictedAppsPerRow) { - mAdapter = adapter; - mComponentToAppMap = componentToAppMap; - mNumPredictedAppsPerRow = numPredictedAppsPerRow; - setVisibility(mPredictedAppComponents.isEmpty() ? View.GONE : View.VISIBLE); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(getExpectedHeight(), - MeasureSpec.EXACTLY)); - } - - public int getExpectedHeight() { - int height = 0; - if (!mPredictedAppComponents.isEmpty()) { - height += Launcher.getLauncher(getContext()) - .getDeviceProfile().allAppsCellHeightPx; - height += getPaddingTop() + getPaddingBottom(); - } - return height; - } - - public void setShowDivider(boolean showDivider) { - mShowDivider = showDivider; - int paddingBottom = showDivider ? getResources() - .getDimensionPixelSize(R.dimen.all_apps_prediction_row_divider_height) : 0; - setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), paddingBottom); - } - - /** - * Sets the number of apps per row. - */ - public void setNumAppsPerRow(int numPredictedAppsPerRow) { - if (mNumPredictedAppsPerRow != numPredictedAppsPerRow) { - mNumPredictedAppsPerRow = numPredictedAppsPerRow; - onPredictionsUpdated(); - } - } - - /** - * Returns the predicted apps. - */ - public List<AppInfo> getPredictedApps() { - return mPredictedApps; - } - - /** - * Sets the current set of predicted apps. - * - * This can be called before we get the full set of applications, we should merge the results - * only in onPredictionsUpdated() which is idempotent. - * - * If the number of predicted apps is the same as the previous list of predicted apps, - * we can optimize by swapping them in place. - */ - public void setPredictedApps(List<ComponentKeyMapper<AppInfo>> apps) { - mPredictedAppComponents.clear(); - mPredictedAppComponents.addAll(apps); - mPredictedApps.clear(); - mPredictedApps.addAll(processPredictedAppComponents(mPredictedAppComponents)); - onPredictionsUpdated(); - } - - private void onPredictionsUpdated() { - int childCountBefore = getChildCount(); - if (getChildCount() != mNumPredictedAppsPerRow) { - while (getChildCount() > mNumPredictedAppsPerRow) { - removeViewAt(0); - } - while (getChildCount() < mNumPredictedAppsPerRow) { - AllAppsGridAdapter.ViewHolder holder = mAdapter - .onCreateViewHolder(this, AllAppsGridAdapter.VIEW_TYPE_ICON); - BubbleTextView icon = (BubbleTextView) holder.itemView; - LinearLayout.LayoutParams params = - new LayoutParams(0, icon.getLayoutParams().height); - params.weight = 1; - icon.setLayoutParams(params); - addView(icon); - } - } - - for (int i = 0; i < getChildCount(); i++) { - BubbleTextView icon = (BubbleTextView) getChildAt(i); - icon.reset(); - if (mPredictedApps.size() > i) { - icon.setVisibility(View.VISIBLE); - icon.applyFromApplicationInfo(mPredictedApps.get(i)); - } else { - icon.setVisibility(View.INVISIBLE); - } - } - - if (getChildCount() > 0 && childCountBefore == 0 - || getChildCount() == 0 && childCountBefore > 0) { - // setting up header to adjust the height - // only necessary if childcount switches from/to 0 - Launcher.getLauncher(getContext()).getAppsView().setupHeader(); - } - } - - /** - * Refreshes the app icons in the row view, while preserving the same set of predictions. - */ - public void onAppsUpdated() { - for (int i = 0; i < getChildCount(); i++) { - View child = getChildAt(i); - if (!(child instanceof BubbleTextView)) { - continue; - } - if (i >= mPredictedApps.size()) { - break; - } - BubbleTextView icon = (BubbleTextView) getChildAt(i); - icon.reset(); - icon.applyFromApplicationInfo(mPredictedApps.get(i)); - } - } - - private List<AppInfo> processPredictedAppComponents( - List<ComponentKeyMapper<AppInfo>> components) { - if (mComponentToAppMap.isEmpty()) { - // Apps have not been bound yet. - return Collections.emptyList(); - } - - List<AppInfo> predictedApps = new ArrayList<>(); - for (ComponentKeyMapper<AppInfo> mapper : components) { - AppInfo info = mapper.getItem(mComponentToAppMap); - if (info != null) { - predictedApps.add(info); - } else { - if (FeatureFlags.IS_DOGFOOD_BUILD) { - Log.e(TAG, "Predicted app not found: " + mapper); - } - } - // Stop at the number of predicted apps - if (predictedApps.size() == mNumPredictedAppsPerRow) { - break; - } - } - return predictedApps; - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - - if (mShowDivider) { - int side = getResources().getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin); - int y = getHeight() - (getPaddingBottom() / 2); - int x1 = getPaddingLeft() + side; - int x2 = getWidth() - getPaddingRight() - side; - canvas.drawLine(x1, y, x2, y, mPaint); - } - } - - @Override - public void fillInLogContainerData(View v, ItemInfo info, LauncherLogProto.Target target, - LauncherLogProto.Target targetParent) { - for (int i = 0; i < mPredictedApps.size(); i++) { - AppInfo appInfo = mPredictedApps.get(i); - if (appInfo == info) { - targetParent.containerType = LauncherLogProto.ContainerType.PREDICTION; - target.predictedRank = i; - break; - } - } - } -} diff --git a/src/com/android/launcher3/allapps/SearchUiManager.java b/src/com/android/launcher3/allapps/SearchUiManager.java index f562b6aa0..bb17ed5e2 100644 --- a/src/com/android/launcher3/allapps/SearchUiManager.java +++ b/src/com/android/launcher3/allapps/SearchUiManager.java @@ -35,12 +35,6 @@ public interface SearchUiManager { @NonNull SpringAnimation getSpringForFling(); /** - * Notifies the search manager that the apps-list has changed and the search UI should be - * updated accordingly. - */ - void refreshSearchResult(); - - /** * Notifies the search manager to close any active search session. */ void reset(); diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java index 6f07eebc6..a56c8b816 100644 --- a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java +++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java @@ -21,7 +21,6 @@ import android.support.animation.FloatValueHolder; import android.support.animation.SpringAnimation; import android.support.animation.SpringForce; import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.text.Selection; import android.text.Spannable; import android.text.SpannableString; @@ -37,6 +36,7 @@ import com.android.launcher3.ExtendedEditText; import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.allapps.AllAppsContainerView; +import com.android.launcher3.allapps.AllAppsStore; import com.android.launcher3.allapps.AlphabeticalAppsList; import com.android.launcher3.allapps.SearchUiManager; import com.android.launcher3.graphics.TintedDrawableSpan; @@ -48,7 +48,8 @@ import java.util.ArrayList; * Layout to contain the All-apps search UI. */ public class AppsSearchContainerLayout extends FrameLayout - implements SearchUiManager, AllAppsSearchBarController.Callbacks { + implements SearchUiManager, AllAppsSearchBarController.Callbacks, + AllAppsStore.OnUpdateListener { private final Launcher mLauncher; private final int mMinHeight; @@ -111,9 +112,22 @@ public class AppsSearchContainerLayout extends FrameLayout } @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mLauncher.getAppsView().getAppsStore().addUpdateListener(this); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + mLauncher.getAppsView().getAppsStore().removeUpdateListener(this); + } + + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - if (!mLauncher.getDeviceProfile().isVerticalBarLayout()) { - getLayoutParams().height = mLauncher.getDragLayer().getInsets().top + mMinHeight; + DeviceProfile dp = mLauncher.getDeviceProfile(); + if (!dp.isVerticalBarLayout()) { + getLayoutParams().height = dp.getInsets().top + mMinHeight; } super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @@ -134,7 +148,7 @@ public class AppsSearchContainerLayout extends FrameLayout } @Override - public void refreshSearchResult() { + public void onAppsUpdated() { mSearchBarController.refreshSearchResult(); } @@ -198,7 +212,7 @@ public class AppsSearchContainerLayout extends FrameLayout int oldLeft, int oldTop, int oldRight, int oldBottom) { DeviceProfile dp = mLauncher.getDeviceProfile(); if (!dp.isVerticalBarLayout()) { - Rect insets = mLauncher.getDragLayer().getInsets(); + Rect insets = dp.getInsets(); int hotseatBottom = bottom - dp.hotseatBarBottomPaddingPx - insets.bottom; int searchTopMargin = insets.top + (mMinHeight - mSearchBoxHeight) + ((MarginLayoutParams) getLayoutParams()).bottomMargin; diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java index 677694f74..a32f6b1dc 100644 --- a/src/com/android/launcher3/dragndrop/DragLayer.java +++ b/src/com/android/launcher3/dragndrop/DragLayer.java @@ -52,7 +52,6 @@ import com.android.launcher3.folder.Folder; import com.android.launcher3.folder.FolderIcon; import com.android.launcher3.keyboard.ViewGroupFocusHelper; import com.android.launcher3.uioverrides.UiFactory; -import com.android.launcher3.util.Themes; import com.android.launcher3.util.Thunk; import com.android.launcher3.util.TouchController; diff --git a/src/com/android/launcher3/graphics/GradientView.java b/src/com/android/launcher3/graphics/GradientView.java index bacb06323..6253e1807 100644 --- a/src/com/android/launcher3/graphics/GradientView.java +++ b/src/com/android/launcher3/graphics/GradientView.java @@ -75,7 +75,7 @@ public class GradientView extends View implements WallpaperColorInfo.OnChangeLis this.mMaskHeight = Utilities.pxFromDp(ALPHA_MASK_HEIGHT_DP, dm); this.mMaskWidth = Utilities.pxFromDp(ALPHA_MASK_WIDTH_DP, dm); Launcher launcher = Launcher.getLauncher(context); - this.mAlphaStart = launcher.getDeviceProfile().isVerticalBarLayout() ? 0 : 100; + this.mAlphaStart = 0; this.mScrimColor = Themes.getAttrColor(context, R.attr.allAppsScrimColor); this.mWallpaperColorInfo = WallpaperColorInfo.getInstance(launcher); mAlphaColors = getResources().getInteger(R.integer.extracted_color_gradient_alpha); diff --git a/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java b/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java index f3b0d6126..3e4bd3100 100644 --- a/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java +++ b/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java @@ -22,6 +22,7 @@ import android.view.Gravity; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewConfiguration; +import android.view.accessibility.AccessibilityManager; import android.widget.FrameLayout; import com.android.launcher3.DeviceProfile; @@ -55,6 +56,7 @@ public class WorkspacePageIndicator extends PageIndicator implements Insettable, private final Handler mDelayedLineFadeHandler = new Handler(Looper.getMainLooper()); private final Launcher mLauncher; + private final AccessibilityManager mAccessibilityManager; private boolean mShouldAutoHide = true; @@ -136,6 +138,8 @@ public class WorkspacePageIndicator extends PageIndicator implements Insettable, boolean darkText = WallpaperColorInfo.getInstance(context).supportsDarkText(); mActiveAlpha = darkText ? BLACK_ALPHA : WHITE_ALPHA; mLinePaint.setColor(darkText ? Color.BLACK : Color.WHITE); + mAccessibilityManager = (AccessibilityManager) + getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); } @Override @@ -249,7 +253,7 @@ public class WorkspacePageIndicator extends PageIndicator implements Insettable, FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams(); if (mIsLandscapeUi) { - if (insets.left > insets.right) { + if (grid.isSeascape()) { lp.leftMargin = grid.hotseatBarSidePaddingPx; lp.rightMargin = insets.right; lp.gravity = Gravity.RIGHT | Gravity.BOTTOM; @@ -274,7 +278,7 @@ public class WorkspacePageIndicator extends PageIndicator implements Insettable, setBackgroundResource(0); setOnFocusChangeListener(null); - setOnClickListener(null); + setOnClickListener(mAccessibilityManager.isTouchExplorationEnabled() ? this : null); } setLayoutParams(lp); diff --git a/src/com/android/launcher3/util/ComponentKeyMapper.java b/src/com/android/launcher3/util/ComponentKeyMapper.java index 916176ac4..a7f0d764e 100644 --- a/src/com/android/launcher3/util/ComponentKeyMapper.java +++ b/src/com/android/launcher3/util/ComponentKeyMapper.java @@ -18,8 +18,6 @@ package com.android.launcher3.util; import android.support.annotation.Nullable; -import java.util.ArrayList; -import java.util.List; import java.util.Map; public class ComponentKeyMapper<T> { diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java index c857bf6a0..744125e15 100644 --- a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java +++ b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java @@ -61,10 +61,4 @@ public class UiFactory { } public static void resetOverview(Launcher launcher) { } - - public static Bundle getActivityLaunchOptions(Launcher launcher, View v) { - return launcher.getDefaultActivityLaunchOptions(v); - } - - public static void registerRemoteAnimations(Launcher launcher) { } } |