Merge sc-qpr1-dev-plus-aosp-without-vendor@7810918
Bug: 205056467 Merged-In: I40bef9eb41bfedf73ac4bd0ff0050833d2a9623c Change-Id: Iae5e73b18d8885df51c1fca1ef27e277721a8237
This commit is contained in:
@@ -112,6 +112,7 @@ android_library {
|
||||
"androidx.preference_preference",
|
||||
"androidx.slice_slice-view",
|
||||
"androidx.cardview_cardview",
|
||||
"com.google.android.material_material",
|
||||
"iconloader_base",
|
||||
],
|
||||
manifest: "AndroidManifest-common.xml",
|
||||
|
||||
@@ -145,7 +145,7 @@
|
||||
<activity
|
||||
android:name="com.android.launcher3.settings.SettingsActivity"
|
||||
android:label="@string/settings_button_text"
|
||||
android:theme="@style/HomeSettingsTheme"
|
||||
android:theme="@style/HomeSettings.Theme"
|
||||
android:exported="true"
|
||||
android:autoRemoveFromRecents="true">
|
||||
<intent-filter>
|
||||
|
||||
@@ -22,11 +22,6 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.android.launcher3">
|
||||
|
||||
<permission
|
||||
android:name="${packageName}.permission.HOTSEAT_EDU"
|
||||
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
|
||||
android:protectionLevel="signatureOrSystem" />
|
||||
|
||||
<uses-permission android:name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS" />
|
||||
<uses-permission android:name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"/>
|
||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||
@@ -41,7 +36,6 @@
|
||||
<uses-permission android:name="android.permission.MANAGE_ACCESSIBILITY"/>
|
||||
<uses-permission android:name="android.permission.MONITOR_INPUT"/>
|
||||
|
||||
<uses-permission android:name="${packageName}.permission.HOTSEAT_EDU" />
|
||||
<uses-permission android:name="android.permission.SYSTEM_APPLICATION_OVERLAY" />
|
||||
|
||||
<application android:backupAgent="com.android.launcher3.LauncherBackupAgent"
|
||||
@@ -133,20 +127,6 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".hybridhotseat.HotseatEduActivity"
|
||||
android:theme="@android:style/Theme.NoDisplay"
|
||||
android:noHistory="true"
|
||||
android:launchMode="singleTask"
|
||||
android:clearTaskOnLaunch="true"
|
||||
android:permission="${packageName}.permission.HOTSEAT_EDU"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="com.android.launcher3.action.SHOW_HYBRID_HOTSEAT_EDU"/>
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/*
|
||||
** Copyright 2021, 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.
|
||||
*/
|
||||
-->
|
||||
|
||||
<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:pathData="M 0, 0 C 0.1217, 0.0462, 0.15, 0.4686, 0.1667, 0.66 C 0.1834, 0.8878, 0.1667, 1, 1, 1"/>
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/*
|
||||
** Copyright 2021, 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.
|
||||
*/
|
||||
-->
|
||||
|
||||
<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:pathData="M 0,0 C 0.05, 0, 0.133333, 0.06, 0.166666, 0.4 C 0.208333, 0.82, 0.25, 1, 1, 1"/>
|
||||
@@ -200,6 +200,17 @@ public abstract class BaseQuickstepLauncher extends Launcher
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code LauncherOverlayCallbacks} scroll amount.
|
||||
* Indicates transition progress to -1 screen.
|
||||
* @param progress From 0 to 1.
|
||||
*/
|
||||
@Override
|
||||
public void onScrollChanged(float progress) {
|
||||
super.onScrollChanged(progress);
|
||||
mDepthController.onOverlayScrollChanged(progress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startIntentSenderForResult(IntentSender intent, int requestCode,
|
||||
Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags, Bundle options) {
|
||||
|
||||
@@ -32,7 +32,6 @@ import static com.android.launcher3.Utilities.postAsyncCallback;
|
||||
import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE;
|
||||
import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5;
|
||||
import static com.android.launcher3.anim.Interpolators.DEACCEL_1_7;
|
||||
import static com.android.launcher3.anim.Interpolators.EXAGGERATED_EASE;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_SCRIM_FOR_APP_LAUNCH;
|
||||
import static com.android.launcher3.config.FeatureFlags.KEYGUARD_ANIMATION;
|
||||
@@ -72,6 +71,7 @@ import android.view.SurfaceControl;
|
||||
import android.view.View;
|
||||
import android.view.ViewRootImpl;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.view.animation.PathInterpolator;
|
||||
|
||||
@@ -142,21 +142,11 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
private static final String CONTROL_REMOTE_APP_TRANSITION_PERMISSION =
|
||||
"android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS";
|
||||
|
||||
private static final long APP_LAUNCH_DURATION = 450;
|
||||
// Use a shorter duration for x or y translation to create a curve effect
|
||||
private static final long APP_LAUNCH_CURVED_DURATION = 250;
|
||||
private static final long APP_LAUNCH_DURATION = 500;
|
||||
|
||||
private static final long APP_LAUNCH_ALPHA_DURATION = 50;
|
||||
private static final long APP_LAUNCH_ALPHA_START_DELAY = 25;
|
||||
|
||||
// We scale the durations for the downward app launch animations (minus the scale animation).
|
||||
private static final float APP_LAUNCH_DOWN_DUR_SCALE_FACTOR = 0.8f;
|
||||
private static final long APP_LAUNCH_DOWN_DURATION =
|
||||
(long) (APP_LAUNCH_DURATION * APP_LAUNCH_DOWN_DUR_SCALE_FACTOR);
|
||||
private static final long APP_LAUNCH_DOWN_CURVED_DURATION =
|
||||
(long) (APP_LAUNCH_CURVED_DURATION * APP_LAUNCH_DOWN_DUR_SCALE_FACTOR);
|
||||
private static final long APP_LAUNCH_ALPHA_DOWN_DURATION =
|
||||
(long) (APP_LAUNCH_ALPHA_DURATION * APP_LAUNCH_DOWN_DUR_SCALE_FACTOR);
|
||||
|
||||
public static final int ANIMATION_NAV_FADE_IN_DURATION = 266;
|
||||
public static final int ANIMATION_NAV_FADE_OUT_DURATION = 133;
|
||||
public static final long ANIMATION_DELAY_NAV_FADE_IN =
|
||||
@@ -166,9 +156,6 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
public static final Interpolator NAV_FADE_OUT_INTERPOLATOR =
|
||||
new PathInterpolator(0.2f, 0f, 1f, 1f);
|
||||
|
||||
private static final long CROP_DURATION = 375;
|
||||
private static final long RADIUS_DURATION = 375;
|
||||
|
||||
public static final int RECENTS_LAUNCH_DURATION = 336;
|
||||
private static final int LAUNCHER_RESUME_START_DELAY = 100;
|
||||
private static final int CLOSING_TRANSITION_DURATION_MS = 250;
|
||||
@@ -222,6 +209,9 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
// Will never be larger than MAX_NUM_TASKS
|
||||
private LinkedHashMap<Integer, Pair<Integer, Integer>> mTaskStartParams;
|
||||
|
||||
private final Interpolator mOpeningXInterpolator;
|
||||
private final Interpolator mOpeningInterpolator;
|
||||
|
||||
public QuickstepTransitionManager(Context context) {
|
||||
mLauncher = Launcher.cast(Launcher.getLauncher(context));
|
||||
mDragLayer = mLauncher.getDragLayer();
|
||||
@@ -248,6 +238,10 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
SystemUiProxy.INSTANCE.get(mLauncher).setStartingWindowListener(
|
||||
mStartingWindowListener);
|
||||
}
|
||||
|
||||
mOpeningXInterpolator = AnimationUtils.loadInterpolator(context, R.interpolator.app_open_x);
|
||||
mOpeningInterpolator = AnimationUtils.loadInterpolator(context,
|
||||
R.interpolator.three_point_fast_out_extra_slow_in);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -651,27 +645,29 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
final float finalShadowRadius = appTargetsAreTranslucent ? 0 : mMaxShadowRadius;
|
||||
|
||||
MultiValueUpdateListener listener = new MultiValueUpdateListener() {
|
||||
FloatProp mDx = new FloatProp(0, prop.dX, 0, prop.xDuration, AGGRESSIVE_EASE);
|
||||
FloatProp mDy = new FloatProp(0, prop.dY, 0, prop.yDuration, AGGRESSIVE_EASE);
|
||||
FloatProp mDx = new FloatProp(0, prop.dX, 0, APP_LAUNCH_DURATION,
|
||||
mOpeningXInterpolator);
|
||||
FloatProp mDy = new FloatProp(0, prop.dY, 0, APP_LAUNCH_DURATION,
|
||||
mOpeningInterpolator);
|
||||
|
||||
FloatProp mIconScaleToFitScreen = new FloatProp(prop.initialAppIconScale,
|
||||
prop.finalAppIconScale, 0, APP_LAUNCH_DURATION, EXAGGERATED_EASE);
|
||||
prop.finalAppIconScale, 0, APP_LAUNCH_DURATION, mOpeningInterpolator);
|
||||
FloatProp mIconAlpha = new FloatProp(prop.iconAlphaStart, 0f,
|
||||
APP_LAUNCH_ALPHA_START_DELAY, prop.alphaDuration, LINEAR);
|
||||
APP_LAUNCH_ALPHA_START_DELAY, APP_LAUNCH_ALPHA_DURATION, LINEAR);
|
||||
|
||||
FloatProp mWindowRadius = new FloatProp(initialWindowRadius, finalWindowRadius, 0,
|
||||
RADIUS_DURATION, EXAGGERATED_EASE);
|
||||
APP_LAUNCH_DURATION, mOpeningInterpolator);
|
||||
FloatProp mShadowRadius = new FloatProp(0, finalShadowRadius, 0,
|
||||
APP_LAUNCH_DURATION, EXAGGERATED_EASE);
|
||||
APP_LAUNCH_DURATION, mOpeningInterpolator);
|
||||
|
||||
FloatProp mCropRectCenterX = new FloatProp(prop.cropCenterXStart, prop.cropCenterXEnd,
|
||||
0, CROP_DURATION, EXAGGERATED_EASE);
|
||||
0, APP_LAUNCH_DURATION, mOpeningInterpolator);
|
||||
FloatProp mCropRectCenterY = new FloatProp(prop.cropCenterYStart, prop.cropCenterYEnd,
|
||||
0, CROP_DURATION, EXAGGERATED_EASE);
|
||||
0, APP_LAUNCH_DURATION, mOpeningInterpolator);
|
||||
FloatProp mCropRectWidth = new FloatProp(prop.cropWidthStart, prop.cropWidthEnd, 0,
|
||||
CROP_DURATION, EXAGGERATED_EASE);
|
||||
APP_LAUNCH_DURATION, mOpeningInterpolator);
|
||||
FloatProp mCropRectHeight = new FloatProp(prop.cropHeightStart, prop.cropHeightEnd, 0,
|
||||
CROP_DURATION, EXAGGERATED_EASE);
|
||||
APP_LAUNCH_DURATION, mOpeningInterpolator);
|
||||
|
||||
FloatProp mNavFadeOut = new FloatProp(1f, 0f, 0, ANIMATION_NAV_FADE_OUT_DURATION,
|
||||
NAV_FADE_OUT_INTERPOLATOR);
|
||||
@@ -873,22 +869,23 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
WIDGET_CROSSFADE_DURATION_MILLIS / 2 /* delay */,
|
||||
WIDGET_CROSSFADE_DURATION_MILLIS / 2 /* duration */, LINEAR);
|
||||
final FloatProp mWindowRadius = new FloatProp(initialWindowRadius, finalWindowRadius,
|
||||
0 /* start */, RADIUS_DURATION, LINEAR);
|
||||
final FloatProp mCornerRadiusProgress = new FloatProp(0, 1, 0, RADIUS_DURATION, LINEAR);
|
||||
0 /* start */, APP_LAUNCH_DURATION, mOpeningInterpolator);
|
||||
final FloatProp mCornerRadiusProgress = new FloatProp(0, 1, 0, APP_LAUNCH_DURATION,
|
||||
mOpeningInterpolator);
|
||||
|
||||
// Window & widget background positioning bounds
|
||||
final FloatProp mDx = new FloatProp(widgetBackgroundBounds.centerX(),
|
||||
windowTargetBounds.centerX(), 0 /* delay */, APP_LAUNCH_CURVED_DURATION,
|
||||
EXAGGERATED_EASE);
|
||||
windowTargetBounds.centerX(), 0 /* delay */, APP_LAUNCH_DURATION,
|
||||
mOpeningXInterpolator);
|
||||
final FloatProp mDy = new FloatProp(widgetBackgroundBounds.centerY(),
|
||||
windowTargetBounds.centerY(), 0 /* delay */, APP_LAUNCH_DURATION,
|
||||
EXAGGERATED_EASE);
|
||||
mOpeningInterpolator);
|
||||
final FloatProp mWidth = new FloatProp(widgetBackgroundBounds.width(),
|
||||
windowTargetBounds.width(), 0 /* delay */, APP_LAUNCH_DURATION,
|
||||
EXAGGERATED_EASE);
|
||||
mOpeningInterpolator);
|
||||
final FloatProp mHeight = new FloatProp(widgetBackgroundBounds.height(),
|
||||
windowTargetBounds.height(), 0 /* delay */, APP_LAUNCH_DURATION,
|
||||
EXAGGERATED_EASE);
|
||||
mOpeningInterpolator);
|
||||
|
||||
final FloatProp mNavFadeOut = new FloatProp(1f, 0f, 0, ANIMATION_NAV_FADE_OUT_DURATION,
|
||||
NAV_FADE_OUT_INTERPOLATOR);
|
||||
@@ -1424,10 +1421,6 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
public final float dX;
|
||||
public final float dY;
|
||||
|
||||
public final long xDuration;
|
||||
public final long yDuration;
|
||||
public final long alphaDuration;
|
||||
|
||||
public final float initialAppIconScale;
|
||||
public final float finalAppIconScale;
|
||||
|
||||
@@ -1459,14 +1452,6 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
dX = centerX - launcherIconBounds.centerX();
|
||||
dY = centerY - launcherIconBounds.centerY();
|
||||
|
||||
boolean useUpwardAnimation = launcherIconBounds.top > centerY
|
||||
|| Math.abs(dY) < dp.cellHeightPx;
|
||||
xDuration = useUpwardAnimation ? APP_LAUNCH_CURVED_DURATION
|
||||
: APP_LAUNCH_DOWN_DURATION;
|
||||
yDuration = useUpwardAnimation ? APP_LAUNCH_DURATION
|
||||
: APP_LAUNCH_DOWN_CURVED_DURATION;
|
||||
alphaDuration = useUpwardAnimation ? APP_LAUNCH_ALPHA_DURATION
|
||||
: APP_LAUNCH_ALPHA_DOWN_DURATION;
|
||||
iconAlphaStart = hasSplashScreen && !hasDifferentAppIcon ? 0 : 1f;
|
||||
|
||||
final int windowIconSize = ResourceUtils.getDimenByName("starting_surface_icon_size",
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.hybridhotseat;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.android.launcher3.BaseActivity;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.uioverrides.QuickstepLauncher;
|
||||
import com.android.launcher3.util.ActivityTracker;
|
||||
|
||||
/**
|
||||
* Proxy activity to return user to home screen and show halfsheet education
|
||||
*/
|
||||
public class HotseatEduActivity extends Activity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
Intent homeIntent = new Intent(Intent.ACTION_MAIN)
|
||||
.addCategory(Intent.CATEGORY_HOME)
|
||||
.setPackage(getPackageName())
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
|
||||
Launcher.ACTIVITY_TRACKER.registerCallback(new HotseatActivityTracker());
|
||||
startActivity(homeIntent);
|
||||
finish();
|
||||
}
|
||||
|
||||
static class HotseatActivityTracker<T extends QuickstepLauncher> implements
|
||||
ActivityTracker.SchedulerCallback {
|
||||
|
||||
@Override
|
||||
public boolean init(BaseActivity activity, boolean alreadyOnHome) {
|
||||
QuickstepLauncher launcher = (QuickstepLauncher) activity;
|
||||
if (launcher != null) {
|
||||
launcher.getHotseatPredictionController().showEdu();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import android.animation.ObjectAnimator;
|
||||
import android.os.IBinder;
|
||||
import android.os.SystemProperties;
|
||||
import android.util.FloatProperty;
|
||||
import android.view.AttachedSurfaceControl;
|
||||
import android.view.CrossWindowBlurListeners;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.View;
|
||||
@@ -108,6 +109,13 @@ public class DepthController implements StateHandler<LauncherState>,
|
||||
}
|
||||
};
|
||||
|
||||
private final Runnable mOpaquenessListener = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
dispatchTransactionSurface(mDepth);
|
||||
}
|
||||
};
|
||||
|
||||
private final Launcher mLauncher;
|
||||
/**
|
||||
* Blur radius when completely zoomed out, in pixels.
|
||||
@@ -116,6 +124,10 @@ public class DepthController implements StateHandler<LauncherState>,
|
||||
private boolean mCrossWindowBlursEnabled;
|
||||
private WallpaperManagerCompat mWallpaperManager;
|
||||
private SurfaceControl mSurface;
|
||||
/**
|
||||
* How visible the -1 overlay is, from 0 to 1.
|
||||
*/
|
||||
private float mOverlayScrollProgress;
|
||||
/**
|
||||
* Ratio from 0 to 1, where 0 is fully zoomed out, and 1 is zoomed in.
|
||||
* @see android.service.wallpaper.WallpaperService.Engine#onZoomChanged(float)
|
||||
@@ -150,23 +162,28 @@ public class DepthController implements StateHandler<LauncherState>,
|
||||
if (windowToken != null) {
|
||||
mWallpaperManager.setWallpaperZoomOut(windowToken, mDepth);
|
||||
}
|
||||
CrossWindowBlurListeners.getInstance().addListener(mLauncher.getMainExecutor(),
|
||||
mCrossWindowBlurListener);
|
||||
onAttached();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(View view) {
|
||||
CrossWindowBlurListeners.getInstance().removeListener(mCrossWindowBlurListener);
|
||||
mLauncher.getScrimView().removeOpaquenessListener(mOpaquenessListener);
|
||||
}
|
||||
};
|
||||
mLauncher.getRootView().addOnAttachStateChangeListener(mOnAttachListener);
|
||||
if (mLauncher.getRootView().isAttachedToWindow()) {
|
||||
CrossWindowBlurListeners.getInstance().addListener(mLauncher.getMainExecutor(),
|
||||
mCrossWindowBlurListener);
|
||||
onAttached();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void onAttached() {
|
||||
CrossWindowBlurListeners.getInstance().addListener(mLauncher.getMainExecutor(),
|
||||
mCrossWindowBlurListener);
|
||||
mLauncher.getScrimView().addOpaquenessListener(mOpaquenessListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if the underlying activity is started or not
|
||||
*/
|
||||
@@ -251,12 +268,24 @@ public class DepthController implements StateHandler<LauncherState>,
|
||||
}
|
||||
}
|
||||
|
||||
public void onOverlayScrollChanged(float progress) {
|
||||
// Round out the progress to dedupe frequent, non-perceptable updates
|
||||
int progressI = (int) (progress * 256);
|
||||
float progressF = Utilities.boundToRange(progressI / 256f, 0f, 1f);
|
||||
if (Float.compare(mOverlayScrollProgress, progressF) == 0) {
|
||||
return;
|
||||
}
|
||||
mOverlayScrollProgress = progressF;
|
||||
dispatchTransactionSurface(mDepth);
|
||||
}
|
||||
|
||||
private boolean dispatchTransactionSurface(float depth) {
|
||||
boolean supportsBlur = BlurUtils.supportsBlursOnWindows();
|
||||
if (supportsBlur && (mSurface == null || !mSurface.isValid())) {
|
||||
return false;
|
||||
}
|
||||
ensureDependencies();
|
||||
depth = Math.max(depth, mOverlayScrollProgress);
|
||||
IBinder windowToken = mLauncher.getRootView().getWindowToken();
|
||||
if (windowToken != null) {
|
||||
mWallpaperManager.setWallpaperZoomOut(windowToken, depth);
|
||||
@@ -270,10 +299,15 @@ public class DepthController implements StateHandler<LauncherState>,
|
||||
|
||||
int blur = opaque || isOverview || !mCrossWindowBlursEnabled
|
||||
|| mBlurDisabledForAppLaunch ? 0 : (int) (depth * mMaxBlurRadius);
|
||||
new SurfaceControl.Transaction()
|
||||
SurfaceControl.Transaction transaction = new SurfaceControl.Transaction()
|
||||
.setBackgroundBlurRadius(mSurface, blur)
|
||||
.setOpaque(mSurface, opaque)
|
||||
.apply();
|
||||
.setOpaque(mSurface, opaque);
|
||||
|
||||
AttachedSurfaceControl rootSurfaceControl =
|
||||
mLauncher.getRootView().getRootSurfaceControl();
|
||||
if (rootSurfaceControl != null) {
|
||||
rootSurfaceControl.applyTransactionOnDraw(transaction);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ class QuickstepInteractionHandler implements RemoteViews.InteractionHandler {
|
||||
}
|
||||
}
|
||||
activityOptions.options.setPendingIntentLaunchFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
activityOptions.options.setSplashscreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_ICON);
|
||||
activityOptions.options.setSplashscreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_EMPTY);
|
||||
Object itemInfo = hostView.getTag();
|
||||
if (itemInfo instanceof ItemInfo) {
|
||||
mLauncher.addLaunchCookie((ItemInfo) itemInfo, activityOptions.options);
|
||||
|
||||
@@ -173,7 +173,9 @@ public class FallbackSwipeHandler extends
|
||||
@Override
|
||||
protected void notifyGestureAnimationStartToRecents() {
|
||||
if (mRunningOverHome) {
|
||||
mRecentsView.onGestureAnimationStartOnHome(mGestureState.getRunningTask());
|
||||
if (SysUINavigationMode.getMode(mContext).hasGestures) {
|
||||
mRecentsView.onGestureAnimationStartOnHome(mGestureState.getRunningTask());
|
||||
}
|
||||
} else {
|
||||
super.notifyGestureAnimationStartToRecents();
|
||||
}
|
||||
|
||||
@@ -331,12 +331,14 @@ public class TouchInteractionService extends Service implements PluginListener<O
|
||||
mDeviceState = new RecentsAnimationDeviceState(this, true);
|
||||
mDisplayManager = getSystemService(DisplayManager.class);
|
||||
mTaskbarManager = new TaskbarManager(this);
|
||||
|
||||
mRotationTouchHelper = mDeviceState.getRotationTouchHelper();
|
||||
mDeviceState.addNavigationModeChangedCallback(this::onNavigationModeChanged);
|
||||
mDeviceState.addOneHandedModeChangedCallback(this::onOneHandedModeOverlayChanged);
|
||||
|
||||
// Call runOnUserUnlocked() before any other callbacks to ensure everything is initialized.
|
||||
mDeviceState.runOnUserUnlocked(this::onUserUnlocked);
|
||||
mDeviceState.runOnUserUnlocked(mTaskbarManager::onUserUnlocked);
|
||||
mDeviceState.addNavigationModeChangedCallback(this::onNavigationModeChanged);
|
||||
mDeviceState.addOneHandedModeChangedCallback(this::onOneHandedModeOverlayChanged);
|
||||
|
||||
ProtoTracer.INSTANCE.get(this).add(this);
|
||||
sConnected = true;
|
||||
}
|
||||
|
||||
@@ -1729,10 +1729,10 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
int runningIndex = getCurrentPage();
|
||||
AnimatorSet as = new AnimatorSet();
|
||||
for (int i = 0; i < getTaskViewCount(); i++) {
|
||||
if (runningIndex == i) {
|
||||
View taskView = getTaskViewAt(i);
|
||||
if (runningIndex == i && taskView.getAlpha() != 0) {
|
||||
continue;
|
||||
}
|
||||
View taskView = getTaskViewAt(i);
|
||||
as.play(ObjectAnimator.ofFloat(taskView, View.ALPHA, fadeInChildren ? 0 : 1));
|
||||
}
|
||||
return as;
|
||||
@@ -1768,8 +1768,6 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
// When switching to tasks in quick switch, ensures the snapped page's scroll maintain
|
||||
// invariant between quick switch and overview, to ensure a smooth animation transition.
|
||||
updateGridProperties();
|
||||
} else if (endTarget == GestureState.GestureEndTarget.RECENTS) {
|
||||
setEnableFreeScroll(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1779,7 +1777,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
public void onGestureAnimationEnd() {
|
||||
mGestureActive = false;
|
||||
if (mOrientationState.setGestureActive(false)) {
|
||||
updateOrientationHandler();
|
||||
updateOrientationHandler(/* forceRecreateDragLayerControllers = */ false);
|
||||
}
|
||||
|
||||
setEnableFreeScroll(true);
|
||||
@@ -2910,8 +2908,11 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
boolean isStartShift;
|
||||
if (midpointIndex > -1) {
|
||||
// When there is a midpoint reference task, adjacent tasks have less distance to travel
|
||||
// to reach offscreen. Offset the task position to the task's starting point.
|
||||
int midpointScroll = getScrollForPage(midpointIndex);
|
||||
// to reach offscreen. Offset the task position to the task's starting point, and offset
|
||||
// by current page's scroll diff.
|
||||
int midpointScroll = getScrollForPage(midpointIndex)
|
||||
+ mOrientationHandler.getPrimaryScroll(this) - getScrollForPage(mCurrentPage);
|
||||
|
||||
getPersistentChildPosition(midpointIndex, midpointScroll, taskPosition);
|
||||
float midpointStart = mOrientationHandler.getStart(taskPosition);
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2021 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.
|
||||
-->
|
||||
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- Disabled status of thumb -->
|
||||
<item android:state_enabled="false"
|
||||
android:color="@color/home_settings_thumb_off_color" />
|
||||
<!-- Toggle off status of thumb -->
|
||||
<item android:state_checked="false"
|
||||
android:color="@color/home_settings_thumb_off_color" />
|
||||
<!-- Enabled or toggle on status of thumb -->
|
||||
<item android:color="@color/home_settings_state_on_color" />
|
||||
</selector>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2021 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.
|
||||
-->
|
||||
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- Disabled status of thumb -->
|
||||
<item android:state_enabled="false"
|
||||
android:color="@color/home_settings_track_off_color"
|
||||
android:alpha="?android:attr/disabledAlpha" />
|
||||
<!-- Toggle off status of thumb -->
|
||||
<item android:state_checked="false"
|
||||
android:color="@color/home_settings_track_off_color" />
|
||||
<!-- Enabled or toggle on status of thumb -->
|
||||
<item android:color="@color/home_settings_track_on_color" />
|
||||
</selector>
|
||||
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2021 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.
|
||||
-->
|
||||
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:top="4dp"
|
||||
android:left="4dp"
|
||||
android:right="4dp"
|
||||
android:bottom="4dp">
|
||||
<shape android:shape="oval" >
|
||||
<size android:height="20dp" android:width="20dp" />
|
||||
<solid android:color="@color/home_settings_switch_thumb_color" />
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
||||
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2021 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.
|
||||
-->
|
||||
|
||||
<shape
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle"
|
||||
android:width="52dp"
|
||||
android:height="28dp">
|
||||
|
||||
<solid android:color="@color/home_settings_switch_track_color" />
|
||||
<corners android:radius="35dp" />
|
||||
</shape>
|
||||
@@ -14,18 +14,11 @@
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:drawable="@drawable/rounded_action_button"
|
||||
android:left="@dimen/padded_rounded_button_padding"
|
||||
android:top="@dimen/padded_rounded_button_padding"
|
||||
android:right="@dimen/padded_rounded_button_padding"
|
||||
android:bottom="@dimen/padded_rounded_button_padding">
|
||||
<shape android:shape="rectangle">
|
||||
<corners android:radius="@dimen/rounded_button_radius" />
|
||||
<stroke android:width="1dp"
|
||||
android:color="?androidprv:attr/colorAccentPrimaryVariant" />
|
||||
</shape>
|
||||
</item>
|
||||
android:bottom="@dimen/padded_rounded_button_padding" />
|
||||
</layer-list>
|
||||
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
|
||||
android:shape="rectangle">
|
||||
<corners android:radius="@dimen/rounded_button_radius" />
|
||||
<stroke android:width="1dp" android:color="@color/all_apps_tab_background_selected" />
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="?androidprv:attr/colorAccentPrimaryVariant" />
|
||||
<padding
|
||||
android:left="@dimen/rounded_button_padding"
|
||||
android:right="@dimen/rounded_button_padding" />
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2021 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.
|
||||
-->
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/content_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/app_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:attr/colorPrimary"
|
||||
android:fitsSystemWindows="true"
|
||||
android:outlineAmbientShadowColor="@android:color/transparent"
|
||||
android:outlineSpotShadowColor="@android:color/transparent"
|
||||
android:theme="@style/HomeSettings.CollapsingToolbar">
|
||||
|
||||
<com.google.android.material.appbar.CollapsingToolbarLayout
|
||||
android:id="@+id/collapsing_toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="226dp"
|
||||
android:clipToPadding="false"
|
||||
app:collapsedTitleTextAppearance="@style/HomeSettings.CollapsedToolbarTitle"
|
||||
app:contentScrim="@color/home_settings_header_collapsed"
|
||||
app:expandedTitleMarginEnd="24dp"
|
||||
app:expandedTitleMarginStart="24dp"
|
||||
app:expandedTitleTextAppearance="@style/HomeSettings.ExpandedToolbarTitle"
|
||||
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
|
||||
app:maxLines="3"
|
||||
app:scrimAnimationDuration="50"
|
||||
app:scrimVisibleHeightTrigger="174dp"
|
||||
app:statusBarScrim="@null"
|
||||
app:titleCollapseMode="fade"
|
||||
app:toolbarId="@id/action_bar">
|
||||
|
||||
<Toolbar
|
||||
android:id="@+id/action_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:theme="?android:attr/actionBarTheme"
|
||||
android:transitionName="shared_element_view"
|
||||
app:layout_collapseMode="pin" />
|
||||
|
||||
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/content_frame"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
@@ -27,15 +27,13 @@
|
||||
android:gravity="center"
|
||||
android:padding="16dp"
|
||||
android:background="@drawable/arrow_toast_rounded_background"
|
||||
android:elevation="2dp"
|
||||
android:outlineProvider="none"
|
||||
android:elevation="@dimen/arrow_toast_elevation"
|
||||
android:textColor="@color/arrow_tip_view_content"
|
||||
android:textSize="14sp"/>
|
||||
|
||||
<View
|
||||
android:id="@+id/arrow"
|
||||
android:elevation="2dp"
|
||||
android:outlineProvider="none"
|
||||
android:elevation="@dimen/arrow_toast_elevation"
|
||||
android:layout_width="@dimen/arrow_toast_arrow_width"
|
||||
android:layout_height="10dp"/>
|
||||
</merge>
|
||||
|
||||
@@ -14,10 +14,11 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<merge
|
||||
<com.android.launcher3.notification.NotificationMainView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- header -->
|
||||
<FrameLayout
|
||||
@@ -49,7 +50,7 @@
|
||||
</FrameLayout>
|
||||
|
||||
<!-- Main view -->
|
||||
<com.android.launcher3.notification.NotificationMainView
|
||||
<FrameLayout
|
||||
android:id="@+id/main_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -59,7 +60,6 @@
|
||||
android:id="@+id/text_and_background"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/popupColorPrimary"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="@dimen/notification_padding"
|
||||
@@ -95,5 +95,5 @@
|
||||
android:layout_marginTop="@dimen/notification_padding"
|
||||
android:layout_marginStart="@dimen/notification_icon_padding" />
|
||||
|
||||
</com.android.launcher3.notification.NotificationMainView>
|
||||
</merge>
|
||||
</FrameLayout>
|
||||
</com.android.launcher3.notification.NotificationMainView>
|
||||
@@ -31,12 +31,9 @@
|
||||
android:elevation="@dimen/deep_shortcuts_elevation"
|
||||
android:orientation="vertical"/>
|
||||
|
||||
<LinearLayout
|
||||
<com.android.launcher3.notification.NotificationContainer
|
||||
android:id="@+id/notification_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
android:background="?attr/popupColorPrimary"
|
||||
android:elevation="@dimen/deep_shortcuts_elevation"
|
||||
android:orientation="vertical"/>
|
||||
android:visibility="gone"/>
|
||||
</com.android.launcher3.popup.PopupContainerWithArrow>
|
||||
@@ -18,7 +18,8 @@
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:launcher="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="@dimen/bg_popup_item_width"
|
||||
android:layout_height="@dimen/bg_popup_item_height"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="@dimen/bg_popup_item_height"
|
||||
android:elevation="@dimen/deep_shortcuts_elevation"
|
||||
android:background="@drawable/middle_item_primary"
|
||||
android:theme="@style/PopupItem" >
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2021 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.
|
||||
-->
|
||||
<merge
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:launcher="http://schemas.android.com/apk/res-auto" >
|
||||
|
||||
<com.android.launcher3.BubbleTextView
|
||||
style="@style/BaseIconUnBounded"
|
||||
android:id="@+id/bubble_text"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:gravity="start|center_vertical"
|
||||
android:paddingTop="@dimen/bg_popup_item_vertical_padding"
|
||||
android:paddingBottom="@dimen/bg_popup_item_vertical_padding"
|
||||
android:minHeight="@dimen/bg_popup_item_height"
|
||||
android:textAlignment="viewStart"
|
||||
android:paddingStart="@dimen/deep_shortcuts_text_padding_start"
|
||||
android:paddingEnd="@dimen/popup_padding_end"
|
||||
android:textSize="14sp"
|
||||
android:minLines="1"
|
||||
android:maxLines="2"
|
||||
android:ellipsize="end"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
launcher:iconDisplay="shortcut_popup"
|
||||
launcher:layoutHorizontal="true"
|
||||
android:focusable="false" />
|
||||
|
||||
<View
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="@dimen/system_shortcut_icon_size"
|
||||
android:layout_height="@dimen/system_shortcut_icon_size"
|
||||
android:layout_marginStart="@dimen/system_shortcut_margin_start"
|
||||
android:layout_gravity="start|center_vertical"
|
||||
android:backgroundTint="?android:attr/textColorPrimary"/>
|
||||
</merge>
|
||||
@@ -28,7 +28,7 @@
|
||||
android:layout_marginTop="40dp"
|
||||
android:text="@string/work_apps_paused_title"
|
||||
android:textAlignment="center"
|
||||
android:textSize="22sp" />
|
||||
android:textSize="18sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
/*
|
||||
* Copyright (C) 2021 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>
|
||||
<color name="home_settings_header_accent">@android:color/system_accent1_100</color>
|
||||
<color name="home_settings_header_collapsed">@android:color/system_neutral1_700</color>
|
||||
<color name="home_settings_header_expanded">@android:color/system_neutral1_900</color>
|
||||
|
||||
<color name="home_settings_thumb_off_color">@android:color/system_neutral2_300</color>
|
||||
<color name="home_settings_track_on_color">@android:color/system_accent2_700</color>
|
||||
<color name="home_settings_track_off_color">@android:color/system_neutral1_700</color>
|
||||
</resources>
|
||||
@@ -42,6 +42,16 @@
|
||||
|
||||
<color name="folder_dot_color">@android:color/system_accent2_50</color>
|
||||
|
||||
<color name="home_settings_header_accent">@android:color/system_accent1_600</color>
|
||||
<color name="home_settings_header_collapsed">@android:color/system_neutral1_100</color>
|
||||
<color name="home_settings_header_expanded">@android:color/system_neutral1_50</color>
|
||||
|
||||
<color name="home_settings_state_on_color">@android:color/system_accent1_100</color>
|
||||
<color name="home_settings_state_off_color">@android:color/system_accent2_100</color>
|
||||
<color name="home_settings_thumb_off_color">@android:color/system_neutral2_100</color>
|
||||
<color name="home_settings_track_on_color">@android:color/system_accent1_600</color>
|
||||
<color name="home_settings_track_off_color">@android:color/system_neutral2_600</color>
|
||||
|
||||
<color name="workspace_accent_color_light">@android:color/system_accent1_100</color>
|
||||
<color name="workspace_accent_color_dark">@android:color/system_accent2_600</color>
|
||||
</resources>
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2021 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>
|
||||
<bool name="home_settings_icon_space_reserved">false</bool>
|
||||
<bool name="home_settings_allow_divider">false</bool>
|
||||
</resources>
|
||||
@@ -0,0 +1,95 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/*
|
||||
* Copyright (C) 2021 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>
|
||||
|
||||
<style name="HomeSettings.Theme" parent="@android:style/Theme.DeviceDefault.Settings">
|
||||
<item name="android:listPreferredItemPaddingEnd">16dp</item>
|
||||
<item name="android:listPreferredItemPaddingStart">24dp</item>
|
||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:switchStyle">@style/HomeSettings.SwitchStyle</item>
|
||||
<item name="android:textAppearanceListItem">@style/HomeSettings.PreferenceTitle</item>
|
||||
<item name="android:windowActionBar">false</item>
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="preferenceTheme">@style/HomeSettings.PreferenceTheme</item>
|
||||
</style>
|
||||
|
||||
<style name="HomeSettings.PreferenceTheme" parent="@style/PreferenceThemeOverlay">
|
||||
<item name="preferenceCategoryStyle">@style/HomeSettings.CategoryStyle</item>
|
||||
<item name="preferenceCategoryTitleTextAppearance">@style/HomeSettings.CategoryTitle</item>
|
||||
<item name="preferenceFragmentCompatStyle">@style/HomeSettings.FragmentCompatStyle</item>
|
||||
<item name="preferenceScreenStyle">@style/HomeSettings.PreferenceScreenStyle</item>
|
||||
<item name="preferenceStyle">@style/HomeSettings.PreferenceStyle</item>
|
||||
<item name="switchPreferenceStyle">@style/HomeSettings.SwitchPreferenceStyle</item>
|
||||
</style>
|
||||
|
||||
<style name="HomeSettings.CategoryStyle" parent="@style/Preference.Category.Material">
|
||||
<item name="allowDividerAbove">@bool/home_settings_allow_divider</item>
|
||||
<item name="allowDividerBelow">@bool/home_settings_allow_divider</item>
|
||||
<item name="iconSpaceReserved">@bool/home_settings_icon_space_reserved</item>
|
||||
</style>
|
||||
|
||||
<style name="HomeSettings.PreferenceStyle" parent="@style/Preference.Material">
|
||||
<item name="iconSpaceReserved">@bool/home_settings_icon_space_reserved</item>
|
||||
</style>
|
||||
|
||||
<style name="HomeSettings.PreferenceScreenStyle"
|
||||
parent="@style/Preference.PreferenceScreen.Material">
|
||||
<item name="iconSpaceReserved">@bool/home_settings_icon_space_reserved</item>
|
||||
</style>
|
||||
|
||||
<style name="HomeSettings.SwitchPreferenceStyle"
|
||||
parent="@style/Preference.SwitchPreference.Material">
|
||||
<item name="iconSpaceReserved">@bool/home_settings_icon_space_reserved</item>
|
||||
</style>
|
||||
|
||||
<style name="HomeSettings.SwitchStyle"
|
||||
parent="@android:style/Widget.Material.CompoundButton.Switch">
|
||||
<item name="android:switchMinWidth">52dp</item>
|
||||
<item name="android:thumb">@drawable/home_settings_switch_thumb</item>
|
||||
<item name="android:track">@drawable/home_settings_switch_track</item>
|
||||
</style>
|
||||
|
||||
<style name="HomeSettings.PreferenceTitle"
|
||||
parent="@android:style/TextAppearance.Material.Subhead">
|
||||
<item name="android:fontFamily">google-sans</item>
|
||||
<item name="android:textSize">20sp</item>
|
||||
</style>
|
||||
|
||||
<style name="HomeSettings.CategoryTitle" parent="@android:style/TextAppearance.Material.Body2">
|
||||
<item name="android:fontFamily">google-sans-text-medium</item>
|
||||
</style>
|
||||
|
||||
<style name="HomeSettings.CollapsingToolbar" parent="@style/Theme.MaterialComponents.DayNight">
|
||||
<item name="colorAccent">@color/home_settings_header_accent</item>
|
||||
<item name="colorPrimary">@color/home_settings_header_expanded</item>
|
||||
<item name="elevationOverlayColor">?attr/colorPrimary</item>
|
||||
<item name="elevationOverlayEnabled">true</item>
|
||||
</style>
|
||||
|
||||
<style name="HomeSettings.CollapsedToolbarTitle"
|
||||
parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title">
|
||||
<item name="android:fontFamily">google-sans</item>
|
||||
</style>
|
||||
|
||||
<style name="HomeSettings.ExpandedToolbarTitle" parent="HomeSettings.CollapsedToolbarTitle">
|
||||
<item name="android:textSize">36sp</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -34,6 +34,9 @@
|
||||
<!-- View tag key used to determine if we should fade in the child views.. -->
|
||||
<string name="popup_container_iterate_children" translatable="false">popup_container_iterate_children</string>
|
||||
|
||||
<!-- config used to determine if header protection is supported in AllApps -->
|
||||
<bool name="config_header_protection_supported">false</bool>
|
||||
|
||||
<!-- Workspace -->
|
||||
<!-- The duration (in ms) of the fade animation on the object outlines, used when
|
||||
we are dragging objects around on the home screen. -->
|
||||
|
||||
@@ -109,6 +109,7 @@
|
||||
<dimen name="all_apps_tip_bottom_margin">8dp</dimen>
|
||||
<!-- The size of corner radius of the arrow in the arrow toast. -->
|
||||
<dimen name="arrow_toast_corner_radius">2dp</dimen>
|
||||
<dimen name="arrow_toast_elevation">2dp</dimen>
|
||||
<dimen name="arrow_toast_arrow_width">10dp</dimen>
|
||||
|
||||
<!-- Search bar in All Apps -->
|
||||
@@ -196,6 +197,7 @@
|
||||
<dimen name="drop_target_text_size">16sp</dimen>
|
||||
<dimen name="drop_target_shadow_elevation">2dp</dimen>
|
||||
<dimen name="drop_target_bar_margin_horizontal">4dp</dimen>
|
||||
<dimen name="drop_target_button_drawable_padding">8dp</dimen>
|
||||
|
||||
<!-- the distance an icon must be dragged before button drop targets accept it -->
|
||||
<dimen name="drag_distanceThreshold">30dp</dimen>
|
||||
@@ -241,6 +243,7 @@
|
||||
<dimen name="bg_popup_padding">2dp</dimen>
|
||||
<dimen name="bg_popup_item_width">216dp</dimen>
|
||||
<dimen name="bg_popup_item_height">56dp</dimen>
|
||||
<dimen name="bg_popup_item_vertical_padding">12dp</dimen>
|
||||
<dimen name="pre_drag_view_scale">6dp</dimen>
|
||||
<!-- an icon with shortcuts must be dragged this far before the container is removed. -->
|
||||
<dimen name="deep_shortcuts_start_drag_threshold">16dp</dimen>
|
||||
@@ -271,6 +274,8 @@
|
||||
|
||||
<!-- Notifications -->
|
||||
<dimen name="bg_round_rect_radius">8dp</dimen>
|
||||
<dimen name="notification_max_trans">8dp</dimen>
|
||||
<dimen name="notification_space">8dp</dimen>
|
||||
<dimen name="notification_padding">16dp</dimen>
|
||||
<dimen name="notification_padding_top">18dp</dimen>
|
||||
<dimen name="notification_header_text_size">14sp</dimen>
|
||||
@@ -331,4 +336,5 @@
|
||||
<dimen name="search_row_icon_size">48dp</dimen>
|
||||
<dimen name="search_row_small_icon_size">32dp</dimen>
|
||||
<dimen name="padded_rounded_button_padding">8dp</dimen>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -153,6 +153,7 @@
|
||||
|
||||
<!-- All applications label -->
|
||||
<string name="all_apps_button_label">Apps list</string>
|
||||
<string name="all_apps_search_results">Search results</string>
|
||||
<string name="all_apps_button_personal_label">Personal apps list</string>
|
||||
<string name="all_apps_button_work_label">Work apps list</string>
|
||||
|
||||
@@ -199,8 +200,11 @@
|
||||
<!-- Error text that lets a user know that the widget can't load. -->
|
||||
<string name="gadget_error_text">Can\'t load widget</string>
|
||||
|
||||
<!-- Button text. This button lets a user change a widget's settings. -->
|
||||
<string name="gadget_setup_text">Widget settings</string>
|
||||
|
||||
<!-- Instructional text to encourage a user to finish setting up the widget. -->
|
||||
<string name="gadget_setup_text">Tap to finish setup</string>
|
||||
<string name="gadget_complete_setup_text">Tap to finish setup</string>
|
||||
|
||||
<!-- Text to inform the user that they can't uninstall a system application -->
|
||||
<string name="uninstall_system_app_text">This is a system app and can\'t be uninstalled.</string>
|
||||
|
||||
@@ -147,18 +147,18 @@
|
||||
<style name="AppTheme.Dark.DarkMainColor" parent="@style/LauncherTheme.Dark.DarkMainColor" />
|
||||
<style name="AppTheme.Dark.DarkText" parent="@style/LauncherTheme.Dark.DarkText" />
|
||||
|
||||
<style name="HomeSettingsTheme" parent="@android:style/Theme.DeviceDefault.Settings">
|
||||
<style name="HomeSettings.Theme" parent="@android:style/Theme.DeviceDefault.Settings">
|
||||
<item name="android:navigationBarColor">?android:colorPrimaryDark</item>
|
||||
<item name="android:windowActionBar">false</item>
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="preferenceTheme">@style/HomeSettingsPreferenceTheme</item>
|
||||
<item name="preferenceTheme">@style/HomeSettings.PreferenceTheme</item>
|
||||
</style>
|
||||
|
||||
<style name="HomeSettingsPreferenceTheme" parent="@style/PreferenceThemeOverlay.v14.Material">
|
||||
<item name="preferenceFragmentCompatStyle">@style/HomeSettingsFragmentCompatStyle</item>
|
||||
<style name="HomeSettings.PreferenceTheme" parent="@style/PreferenceThemeOverlay.v14.Material">
|
||||
<item name="preferenceFragmentCompatStyle">@style/HomeSettings.FragmentCompatStyle</item>
|
||||
</style>
|
||||
|
||||
<style name="HomeSettingsFragmentCompatStyle" parent="@style/PreferenceFragment.Material">
|
||||
<style name="HomeSettings.FragmentCompatStyle" parent="@style/PreferenceFragment.Material">
|
||||
<item name="android:layout">@layout/home_settings</item>
|
||||
</style>
|
||||
|
||||
@@ -259,7 +259,7 @@
|
||||
|
||||
<!-- Drop targets -->
|
||||
<style name="DropTargetButtonBase" parent="@android:style/TextAppearance.DeviceDefault">
|
||||
<item name="android:drawablePadding">8dp</item>
|
||||
<item name="android:drawablePadding">@dimen/drop_target_button_drawable_padding</item>
|
||||
<item name="android:padding">14dp</item>
|
||||
<item name="android:textColor">@color/drop_target_text</item>
|
||||
<item name="android:textSize">@dimen/drop_target_text_size</item>
|
||||
|
||||
@@ -66,6 +66,8 @@ public abstract class ButtonDropTarget extends TextView
|
||||
private final int mDragDistanceThreshold;
|
||||
/** The size of the drawable shown in the drop target. */
|
||||
private final int mDrawableSize;
|
||||
/** The padding, in pixels, between the text and drawable. */
|
||||
private final int mDrawablePadding;
|
||||
|
||||
protected CharSequence mText;
|
||||
protected Drawable mDrawable;
|
||||
@@ -85,6 +87,8 @@ public abstract class ButtonDropTarget extends TextView
|
||||
Resources resources = getResources();
|
||||
mDragDistanceThreshold = resources.getDimensionPixelSize(R.dimen.drag_distanceThreshold);
|
||||
mDrawableSize = resources.getDimensionPixelSize(R.dimen.drop_target_text_size);
|
||||
mDrawablePadding = resources.getDimensionPixelSize(
|
||||
R.dimen.drop_target_button_drawable_padding);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -303,6 +307,8 @@ public abstract class ButtonDropTarget extends TextView
|
||||
mTextVisible = isVisible;
|
||||
setText(newText);
|
||||
setCompoundDrawablesRelative(mDrawable, null, null, null);
|
||||
int drawablePadding = mTextVisible ? mDrawablePadding : 0;
|
||||
setCompoundDrawablePadding(drawablePadding);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -99,8 +99,18 @@ public class ExtendedEditText extends EditText {
|
||||
}
|
||||
}
|
||||
|
||||
// inherited class can override to change the appearance of the edit text.
|
||||
public void show() {}
|
||||
/**
|
||||
* Sets whether EditText background should be visible
|
||||
* @param maxAlpha defines the maximum alpha the background should animates to
|
||||
*/
|
||||
public void setBackgroundVisibility(boolean visible, float maxAlpha) {}
|
||||
|
||||
/**
|
||||
* Returns whether a visible background is set on EditText
|
||||
*/
|
||||
public boolean getBackgroundVisibility() {
|
||||
return getBackground() != null;
|
||||
}
|
||||
|
||||
public void showKeyboard() {
|
||||
mShowImeAfterFirstLayout = !showSoftInput();
|
||||
|
||||
@@ -218,7 +218,8 @@ import java.util.stream.Stream;
|
||||
* Default launcher application.
|
||||
*/
|
||||
public class Launcher extends StatefulActivity<LauncherState> implements LauncherExterns,
|
||||
Callbacks, InvariantDeviceProfile.OnIDPChangeListener, PluginListener<OverlayPlugin> {
|
||||
Callbacks, InvariantDeviceProfile.OnIDPChangeListener, PluginListener<OverlayPlugin>,
|
||||
LauncherOverlayCallbacks {
|
||||
public static final String TAG = "Launcher";
|
||||
|
||||
public static final ActivityTracker<Launcher> ACTIVITY_TRACKER = new ActivityTracker<>();
|
||||
@@ -619,7 +620,7 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
|
||||
@Override
|
||||
public void setLauncherOverlay(LauncherOverlay overlay) {
|
||||
if (overlay != null) {
|
||||
overlay.setOverlayCallbacks(new LauncherOverlayCallbacksImpl());
|
||||
overlay.setOverlayCallbacks(this);
|
||||
}
|
||||
mWorkspace.setLauncherOverlay(overlay);
|
||||
}
|
||||
@@ -1123,12 +1124,15 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
|
||||
mAppWidgetHost.setActivityResumed(false);
|
||||
}
|
||||
|
||||
class LauncherOverlayCallbacksImpl implements LauncherOverlayCallbacks {
|
||||
|
||||
public void onScrollChanged(float progress) {
|
||||
if (mWorkspace != null) {
|
||||
mWorkspace.onOverlayScrollChanged(progress);
|
||||
}
|
||||
/**
|
||||
* {@code LauncherOverlayCallbacks} scroll amount.
|
||||
* Indicates transition progress to -1 screen.
|
||||
* @param progress From 0 to 1.
|
||||
*/
|
||||
@Override
|
||||
public void onScrollChanged(float progress) {
|
||||
if (mWorkspace != null) {
|
||||
mWorkspace.onOverlayScrollChanged(progress);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ import android.view.ViewGroup;
|
||||
import com.android.launcher3.CellLayout.ContainerType;
|
||||
import com.android.launcher3.folder.FolderIcon;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
import com.android.launcher3.widget.LauncherAppWidgetHostView;
|
||||
import com.android.launcher3.widget.NavigableAppWidgetHostView;
|
||||
|
||||
public class ShortcutAndWidgetContainer extends ViewGroup implements FolderIcon.FolderIconParent {
|
||||
static final String TAG = "ShortcutAndWidgetContainer";
|
||||
@@ -104,9 +104,9 @@ public class ShortcutAndWidgetContainer extends ViewGroup implements FolderIcon.
|
||||
|
||||
public void setupLp(View child) {
|
||||
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
|
||||
if (child instanceof LauncherAppWidgetHostView) {
|
||||
if (child instanceof NavigableAppWidgetHostView) {
|
||||
DeviceProfile profile = mActivity.getDeviceProfile();
|
||||
((LauncherAppWidgetHostView) child).getWidgetInset(profile, mTempRect);
|
||||
((NavigableAppWidgetHostView) child).getWidgetInset(profile, mTempRect);
|
||||
lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY,
|
||||
profile.appWidgetScale.x, profile.appWidgetScale.y, mBorderSpacing, mTempRect);
|
||||
} else {
|
||||
@@ -129,8 +129,8 @@ public class ShortcutAndWidgetContainer extends ViewGroup implements FolderIcon.
|
||||
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
|
||||
final DeviceProfile dp = mActivity.getDeviceProfile();
|
||||
|
||||
if (child instanceof LauncherAppWidgetHostView) {
|
||||
((LauncherAppWidgetHostView) child).getWidgetInset(dp, mTempRect);
|
||||
if (child instanceof NavigableAppWidgetHostView) {
|
||||
((NavigableAppWidgetHostView) child).getWidgetInset(dp, mTempRect);
|
||||
lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY,
|
||||
dp.appWidgetScale.x, dp.appWidgetScale.y, mBorderSpacing, mTempRect);
|
||||
} else {
|
||||
@@ -178,16 +178,16 @@ public class ShortcutAndWidgetContainer extends ViewGroup implements FolderIcon.
|
||||
*/
|
||||
public void layoutChild(View child) {
|
||||
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
|
||||
if (child instanceof LauncherAppWidgetHostView) {
|
||||
LauncherAppWidgetHostView lahv = (LauncherAppWidgetHostView) child;
|
||||
if (child instanceof NavigableAppWidgetHostView) {
|
||||
NavigableAppWidgetHostView nahv = (NavigableAppWidgetHostView) child;
|
||||
|
||||
// Scale and center the widget to fit within its cells.
|
||||
DeviceProfile profile = mActivity.getDeviceProfile();
|
||||
float scaleX = profile.appWidgetScale.x;
|
||||
float scaleY = profile.appWidgetScale.y;
|
||||
|
||||
lahv.setScaleToFit(Math.min(scaleX, scaleY));
|
||||
lahv.setTranslationForCentering(-(lp.width - (lp.width * scaleX)) / 2.0f,
|
||||
nahv.setScaleToFit(Math.min(scaleX, scaleY));
|
||||
nahv.setTranslationForCentering(-(lp.width - (lp.width * scaleX)) / 2.0f,
|
||||
-(lp.height - (lp.height * scaleY)) / 2.0f);
|
||||
}
|
||||
|
||||
|
||||
@@ -687,8 +687,9 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
CellLayout finalScreen = mWorkspaceScreens.get(finalScreenId);
|
||||
|
||||
// If the final screen is empty, convert it to the extra empty screen
|
||||
if (finalScreen.getShortcutsAndWidgets().getChildCount() == 0 &&
|
||||
!finalScreen.isDropPending()) {
|
||||
if (finalScreen != null
|
||||
&& finalScreen.getShortcutsAndWidgets().getChildCount() == 0
|
||||
&& !finalScreen.isDropPending()) {
|
||||
mWorkspaceScreens.remove(finalScreenId);
|
||||
mScreenOrder.removeValue(finalScreenId);
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
|
||||
import com.android.launcher3.DragSource;
|
||||
import com.android.launcher3.DropTarget.DragObject;
|
||||
import com.android.launcher3.ExtendedEditText;
|
||||
import com.android.launcher3.Insettable;
|
||||
import com.android.launcher3.InsettableFrameLayout;
|
||||
import com.android.launcher3.R;
|
||||
@@ -118,7 +119,8 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
||||
private SpannableStringBuilder mSearchQueryBuilder = null;
|
||||
|
||||
protected boolean mUsingTabs;
|
||||
private boolean mSearchModeWhileUsingTabs = false;
|
||||
private boolean mIsSearching;
|
||||
private boolean mHasWorkApps;
|
||||
|
||||
protected RecyclerViewFastScroller mTouchHandler;
|
||||
protected final Point mFastScrollerOffset = new Point();
|
||||
@@ -132,6 +134,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
||||
private final float mHeaderThreshold;
|
||||
private ScrimView mScrimView;
|
||||
private int mHeaderColor;
|
||||
private int mTabsProtectionAlpha;
|
||||
|
||||
public AllAppsContainerView(Context context) {
|
||||
this(context, null);
|
||||
@@ -189,7 +192,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
||||
int currentPage = state.getInt(BUNDLE_KEY_CURRENT_PAGE, 0);
|
||||
if (currentPage != 0 && mViewPager != null) {
|
||||
mViewPager.setCurrentPage(currentPage);
|
||||
rebindAdapters(true);
|
||||
rebindAdapters();
|
||||
} else {
|
||||
reset(true);
|
||||
}
|
||||
@@ -243,9 +246,10 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
||||
break;
|
||||
}
|
||||
}
|
||||
mHasWorkApps = hasWorkApps;
|
||||
if (!mAH[AdapterHolder.MAIN].appsList.hasFilter()) {
|
||||
rebindAdapters(hasWorkApps);
|
||||
if (hasWorkApps) {
|
||||
rebindAdapters();
|
||||
if (mHasWorkApps) {
|
||||
resetWorkProfile();
|
||||
}
|
||||
}
|
||||
@@ -322,6 +326,8 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
||||
mViewPager.getNextPage() == 0
|
||||
? R.string.all_apps_button_personal_label
|
||||
: R.string.all_apps_button_work_label;
|
||||
} else if (mIsSearching) {
|
||||
descriptionRes = R.string.all_apps_search_results;
|
||||
} else {
|
||||
descriptionRes = R.string.all_apps_button_label;
|
||||
}
|
||||
@@ -370,7 +376,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
||||
});
|
||||
|
||||
mHeader = findViewById(R.id.all_apps_header);
|
||||
rebindAdapters(mUsingTabs, true /* force */);
|
||||
rebindAdapters(true /* force */);
|
||||
|
||||
mSearchContainer = findViewById(R.id.search_container_all_apps);
|
||||
mSearchUiManager = (SearchUiManager) mSearchContainer;
|
||||
@@ -439,11 +445,12 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
||||
}
|
||||
}
|
||||
|
||||
private void rebindAdapters(boolean showTabs) {
|
||||
rebindAdapters(showTabs, false /* force */);
|
||||
private void rebindAdapters() {
|
||||
rebindAdapters(false /* force */);
|
||||
}
|
||||
|
||||
protected void rebindAdapters(boolean showTabs, boolean force) {
|
||||
protected void rebindAdapters(boolean force) {
|
||||
boolean showTabs = mHasWorkApps && !mIsSearching;
|
||||
if (showTabs == mUsingTabs && !force) {
|
||||
return;
|
||||
}
|
||||
@@ -454,7 +461,6 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
||||
mAllAppsStore.unregisterIconContainer(mAH[AdapterHolder.WORK].recyclerView);
|
||||
|
||||
if (mUsingTabs) {
|
||||
setupWorkToggle();
|
||||
mAH[AdapterHolder.MAIN].setup(mViewPager.getChildAt(0), mPersonalMatcher);
|
||||
mAH[AdapterHolder.WORK].setup(mViewPager.getChildAt(1), mWorkMatcher);
|
||||
mAH[AdapterHolder.WORK].recyclerView.setId(R.id.apps_list_view_work);
|
||||
@@ -485,6 +491,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
||||
}
|
||||
|
||||
private void setupWorkToggle() {
|
||||
removeWorkToggle();
|
||||
if (Utilities.ATLEAST_P) {
|
||||
mWorkModeSwitch = (WorkModeSwitch) mLauncher.getLayoutInflater().inflate(
|
||||
R.layout.work_mode_fab, this, false);
|
||||
@@ -497,10 +504,20 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
||||
}
|
||||
}
|
||||
|
||||
private void removeWorkToggle() {
|
||||
if (mWorkModeSwitch == null) return;
|
||||
if (mWorkModeSwitch.getParent() == this) {
|
||||
this.removeView(mWorkModeSwitch);
|
||||
}
|
||||
mWorkModeSwitch = null;
|
||||
}
|
||||
|
||||
private void replaceRVContainer(boolean showTabs) {
|
||||
for (int i = 0; i < mAH.length; i++) {
|
||||
if (mAH[i].recyclerView != null) {
|
||||
mAH[i].recyclerView.setLayoutManager(null);
|
||||
AllAppsRecyclerView rv = mAH[i].recyclerView;
|
||||
if (rv != null) {
|
||||
rv.setLayoutManager(null);
|
||||
rv.setAdapter(null);
|
||||
}
|
||||
}
|
||||
View oldView = getRecyclerViewContainer();
|
||||
@@ -517,8 +534,10 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
||||
mViewPager = (AllAppsPagedView) newView;
|
||||
mViewPager.initParentViews(this);
|
||||
mViewPager.getPageIndicator().setOnActivePageChangedListener(this);
|
||||
setupWorkToggle();
|
||||
} else {
|
||||
mViewPager = null;
|
||||
removeWorkToggle();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -537,14 +556,6 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
||||
mWorkModeSwitch.setWorkTabVisible(currentActivePage == AdapterHolder.WORK
|
||||
&& mAllAppsStore.hasModelFlag(
|
||||
FLAG_HAS_SHORTCUT_PERMISSION | FLAG_QUIET_MODE_CHANGE_PERMISSION));
|
||||
|
||||
if (currentActivePage == AdapterHolder.WORK) {
|
||||
if (mWorkModeSwitch.getParent() == null) {
|
||||
addView(mWorkModeSwitch);
|
||||
}
|
||||
} else {
|
||||
removeView(mWorkModeSwitch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -621,18 +632,15 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
||||
for (int i = 0; i < mAH.length; i++) {
|
||||
mAH[i].adapter.setLastSearchQuery(query);
|
||||
}
|
||||
if (mUsingTabs) {
|
||||
mSearchModeWhileUsingTabs = true;
|
||||
rebindAdapters(false); // hide tabs
|
||||
}
|
||||
mIsSearching = true;
|
||||
rebindAdapters();
|
||||
mHeader.setCollapsed(true);
|
||||
}
|
||||
|
||||
public void onClearSearchResult() {
|
||||
if (mSearchModeWhileUsingTabs) {
|
||||
rebindAdapters(true); // show tabs
|
||||
mSearchModeWhileUsingTabs = false;
|
||||
}
|
||||
mIsSearching = false;
|
||||
rebindAdapters();
|
||||
getActiveRecyclerView().scrollToTop();
|
||||
}
|
||||
|
||||
public void onSearchResultsChanged() {
|
||||
@@ -706,13 +714,12 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
||||
mHeaderPaint.setColor(mHeaderColor);
|
||||
mHeaderPaint.setAlpha((int) (getAlpha() * Color.alpha(mHeaderColor)));
|
||||
if (mHeaderPaint.getColor() != mScrimColor && mHeaderPaint.getColor() != 0) {
|
||||
int bottom = mUsingTabs && mHeader.mHeaderCollapsed ? mHeader.getVisibleBottomBound()
|
||||
: mSearchContainer.getBottom();
|
||||
canvas.drawRect(0, 0, canvas.getWidth(), bottom + getTranslationY(),
|
||||
mHeaderPaint);
|
||||
|
||||
if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && getTranslationY() == 0) {
|
||||
mSearchUiManager.getEditText().setBackground(null);
|
||||
int bottom = (int) (mSearchContainer.getBottom() + getTranslationY());
|
||||
canvas.drawRect(0, 0, canvas.getWidth(), bottom, mHeaderPaint);
|
||||
int tabsHeight = getFloatingHeaderView().getPeripheralProtectionHeight();
|
||||
if (mTabsProtectionAlpha > 0 && tabsHeight != 0) {
|
||||
mHeaderPaint.setAlpha((int) (getAlpha() * mTabsProtectionAlpha));
|
||||
canvas.drawRect(0, bottom, canvas.getWidth(), bottom + tabsHeight, mHeaderPaint);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -792,18 +799,29 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
||||
|
||||
|
||||
protected void updateHeaderScroll(int scrolledOffset) {
|
||||
float prog = Math.max(0, Math.min(1, (float) scrolledOffset / mHeaderThreshold));
|
||||
|
||||
float prog = Utilities.boundToRange((float) scrolledOffset / mHeaderThreshold, 0f, 1f);
|
||||
int viewBG = ColorUtils.blendARGB(mScrimColor, mHeaderProtectionColor, prog);
|
||||
int headerColor = ColorUtils.setAlphaComponent(viewBG,
|
||||
(int) (getSearchView().getAlpha() * 255));
|
||||
if (headerColor != mHeaderColor) {
|
||||
int tabsAlpha = mHeader.getPeripheralProtectionHeight() == 0 ? 0
|
||||
: (int) (Utilities.boundToRange(
|
||||
(scrolledOffset + mHeader.mSnappedScrolledY) / mHeaderThreshold, 0f, 1f)
|
||||
* 255);
|
||||
if (headerColor != mHeaderColor || mTabsProtectionAlpha != tabsAlpha) {
|
||||
mHeaderColor = headerColor;
|
||||
getSearchView().setBackgroundColor(viewBG);
|
||||
getFloatingHeaderView().setHeaderColor(viewBG);
|
||||
mTabsProtectionAlpha = tabsAlpha;
|
||||
invalidateHeader();
|
||||
if (scrolledOffset == 0 && mSearchUiManager.getEditText() != null) {
|
||||
mSearchUiManager.getEditText().show();
|
||||
}
|
||||
if (mSearchUiManager.getEditText() != null) {
|
||||
ExtendedEditText editText = mSearchUiManager.getEditText();
|
||||
boolean bgVisible = editText.getBackgroundVisibility();
|
||||
if (scrolledOffset == 0 && !mIsSearching) {
|
||||
bgVisible = true;
|
||||
} else if (scrolledOffset > mHeaderThreshold) {
|
||||
bgVisible = false;
|
||||
}
|
||||
editText.setBackgroundVisibility(bgVisible, 1 - prog);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -811,7 +829,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
||||
* redraws header protection
|
||||
*/
|
||||
public void invalidateHeader() {
|
||||
if (mScrimView != null && FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
|
||||
if (mScrimView != null && mHeader.isHeaderProtectionSupported()) {
|
||||
mScrimView.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +63,13 @@ public class AllAppsRecyclerView extends BaseRecyclerView {
|
||||
private final SparseIntArray mCachedScrollPositions = new SparseIntArray();
|
||||
private final AllAppsFastScrollHelper mFastScrollHelper;
|
||||
|
||||
|
||||
private final AdapterDataObserver mObserver = new RecyclerView.AdapterDataObserver() {
|
||||
public void onChanged() {
|
||||
mCachedScrollPositions.clear();
|
||||
}
|
||||
};
|
||||
|
||||
// The empty-search result background
|
||||
private AllAppsBackgroundDrawable mEmptySearchBackground;
|
||||
private int mEmptySearchBackgroundTopOffset;
|
||||
@@ -247,12 +254,13 @@ public class AllAppsRecyclerView extends BaseRecyclerView {
|
||||
|
||||
@Override
|
||||
public void setAdapter(Adapter adapter) {
|
||||
if (getAdapter() != null) {
|
||||
getAdapter().unregisterAdapterDataObserver(mObserver);
|
||||
}
|
||||
super.setAdapter(adapter);
|
||||
adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
|
||||
public void onChanged() {
|
||||
mCachedScrollPositions.clear();
|
||||
}
|
||||
});
|
||||
if (adapter != null) {
|
||||
adapter.registerAdapterDataObserver(mObserver);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -17,9 +17,6 @@ package com.android.launcher3.allapps;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.util.ArrayMap;
|
||||
@@ -50,11 +47,10 @@ public class FloatingHeaderView extends LinearLayout implements
|
||||
ValueAnimator.AnimatorUpdateListener, PluginListener<AllAppsRow>, Insettable,
|
||||
OnHeightUpdatedListener {
|
||||
|
||||
private final Rect mClip = new Rect(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE);
|
||||
private final Rect mRVClip = new Rect(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE);
|
||||
private final Rect mHeaderClip = new Rect(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE);
|
||||
private final ValueAnimator mAnimator = ValueAnimator.ofInt(0, 0);
|
||||
private final ValueAnimator mHeaderAnimator = ValueAnimator.ofInt(0, 1).setDuration(100);
|
||||
private final Point mTempOffset = new Point();
|
||||
private final Paint mBGPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private final RecyclerView.OnScrollListener mOnScrollListener =
|
||||
new RecyclerView.OnScrollListener() {
|
||||
@Override
|
||||
@@ -82,19 +78,19 @@ public class FloatingHeaderView extends LinearLayout implements
|
||||
}
|
||||
};
|
||||
|
||||
private final int mHeaderTopPadding;
|
||||
|
||||
protected final Map<AllAppsRow, PluginHeaderRow> mPluginRows = new ArrayMap<>();
|
||||
|
||||
private final int mHeaderTopPadding;
|
||||
private final boolean mHeaderProtectionSupported;
|
||||
|
||||
protected ViewGroup mTabLayout;
|
||||
private AllAppsRecyclerView mMainRV;
|
||||
private AllAppsRecyclerView mWorkRV;
|
||||
private AllAppsRecyclerView mCurrentRV;
|
||||
private ViewGroup mParent;
|
||||
public boolean mHeaderCollapsed;
|
||||
private int mSnappedScrolledY;
|
||||
protected int mSnappedScrolledY;
|
||||
private int mTranslationY;
|
||||
private int mHeaderColor;
|
||||
|
||||
private boolean mForwardToRecyclerView;
|
||||
|
||||
@@ -120,6 +116,8 @@ public class FloatingHeaderView extends LinearLayout implements
|
||||
super(context, attrs);
|
||||
mHeaderTopPadding = context.getResources()
|
||||
.getDimensionPixelSize(R.dimen.all_apps_header_top_padding);
|
||||
mHeaderProtectionSupported = context.getResources().getBoolean(
|
||||
R.bool.config_header_protection_supported);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -138,7 +136,6 @@ public class FloatingHeaderView extends LinearLayout implements
|
||||
}
|
||||
mFixedRows = rows.toArray(new FloatingHeaderRow[rows.size()]);
|
||||
mAllRows = mFixedRows;
|
||||
mHeaderAnimator.addUpdateListener(valueAnimator -> invalidate());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -285,7 +282,7 @@ public class FloatingHeaderView extends LinearLayout implements
|
||||
mHeaderCollapsed = false;
|
||||
}
|
||||
mTranslationY = currentScrollY;
|
||||
} else if (!mHeaderCollapsed) {
|
||||
} else {
|
||||
mTranslationY = currentScrollY - mSnappedScrolledY - mMaxTranslation;
|
||||
|
||||
// update state vars
|
||||
@@ -295,31 +292,10 @@ public class FloatingHeaderView extends LinearLayout implements
|
||||
} else if (mTranslationY <= -mMaxTranslation) { // hide or stay hidden
|
||||
mHeaderCollapsed = true;
|
||||
mSnappedScrolledY = -mMaxTranslation;
|
||||
mHeaderAnimator.setCurrentFraction(0);
|
||||
mHeaderAnimator.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set current header protection background color
|
||||
*/
|
||||
public void setHeaderColor(int color) {
|
||||
mHeaderColor = color;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dispatchDraw(Canvas canvas) {
|
||||
if (mHeaderCollapsed && !mCollapsed && mTabLayout.getVisibility() == VISIBLE
|
||||
&& mHeaderColor != Color.TRANSPARENT && FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
|
||||
mBGPaint.setColor(mHeaderColor);
|
||||
mBGPaint.setAlpha((int) (255 * mHeaderAnimator.getAnimatedFraction()));
|
||||
canvas.drawRect(0, 0, getWidth(), getHeight() + mTranslationY, mBGPaint);
|
||||
}
|
||||
super.dispatchDraw(canvas);
|
||||
}
|
||||
|
||||
protected void applyVerticalMove() {
|
||||
int uncappedTranslationY = mTranslationY;
|
||||
mTranslationY = Math.max(mTranslationY, -mMaxTranslation);
|
||||
@@ -336,11 +312,15 @@ public class FloatingHeaderView extends LinearLayout implements
|
||||
}
|
||||
|
||||
mTabLayout.setTranslationY(mTranslationY);
|
||||
mClip.top = mMaxTranslation + mTranslationY;
|
||||
|
||||
int clipHeight = mHeaderTopPadding - getPaddingBottom();
|
||||
mRVClip.top = mTabsHidden ? clipHeight : 0;
|
||||
mHeaderClip.top = clipHeight;
|
||||
// clipping on a draw might cause additional redraw
|
||||
mMainRV.setClipBounds(mClip);
|
||||
setClipBounds(mHeaderClip);
|
||||
mMainRV.setClipBounds(mRVClip);
|
||||
if (mWorkRV != null) {
|
||||
mWorkRV.setClipBounds(mClip);
|
||||
mWorkRV.setClipBounds(mRVClip);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -421,6 +401,10 @@ public class FloatingHeaderView extends LinearLayout implements
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isHeaderProtectionSupported() {
|
||||
return mHeaderProtectionSupported;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasOverlappingRendering() {
|
||||
return false;
|
||||
@@ -444,10 +428,19 @@ public class FloatingHeaderView extends LinearLayout implements
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns visible height of FloatingHeaderView contents
|
||||
* Returns visible height of FloatingHeaderView contents requiring header protection
|
||||
*/
|
||||
public int getVisibleBottomBound() {
|
||||
return getBottom() + mTranslationY;
|
||||
public int getPeripheralProtectionHeight() {
|
||||
if (!mHeaderProtectionSupported) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// we only want to show protection when work tab is available and header is either
|
||||
// collapsed or animating to/from collapsed state
|
||||
if (mTabsHidden || !mHeaderCollapsed) {
|
||||
return 0;
|
||||
}
|
||||
return Math.max(getHeight() - getPaddingTop() + mTranslationY, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ import android.view.MotionEvent;
|
||||
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.statemanager.StateManager.StateListener;
|
||||
|
||||
/**
|
||||
* AllAppsContainerView with launcher specific callbacks
|
||||
@@ -31,8 +30,6 @@ public class LauncherAllAppsContainerView extends AllAppsContainerView {
|
||||
|
||||
private final Launcher mLauncher;
|
||||
|
||||
private StateListener<LauncherState> mWorkTabListener;
|
||||
|
||||
public LauncherAllAppsContainerView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
@@ -74,14 +71,6 @@ public class LauncherAllAppsContainerView extends AllAppsContainerView {
|
||||
mLauncher.getAllAppsController().setScrollRangeDelta(allAppsStartingPositionY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupHeader() {
|
||||
super.setupHeader();
|
||||
if (mWorkTabListener != null && !mUsingTabs) {
|
||||
mLauncher.getStateManager().removeStateListener(mWorkTabListener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivePageChanged(int currentActivePage) {
|
||||
super.onActivePageChanged(currentActivePage);
|
||||
|
||||
@@ -51,6 +51,7 @@ public class WorkModeSwitch extends Button implements Insettable, View.OnClickLi
|
||||
|
||||
@Nullable
|
||||
private KeyboardInsetAnimationCallback mKeyboardInsetAnimationCallback;
|
||||
private boolean mWorkTabVisible;
|
||||
|
||||
public WorkModeSwitch(Context context) {
|
||||
this(context, null, 0);
|
||||
@@ -91,11 +92,10 @@ public class WorkModeSwitch extends Button implements Insettable, View.OnClickLi
|
||||
*/
|
||||
public void setWorkTabVisible(boolean workTabVisible) {
|
||||
clearAnimation();
|
||||
if (workTabVisible) {
|
||||
mWorkTabVisible = workTabVisible;
|
||||
if (workTabVisible && mWorkEnabled) {
|
||||
setEnabled(true);
|
||||
if (mWorkEnabled) {
|
||||
setVisibility(VISIBLE);
|
||||
}
|
||||
setVisibility(VISIBLE);
|
||||
setAlpha(0);
|
||||
animate().alpha(1).start();
|
||||
} else {
|
||||
@@ -105,7 +105,7 @@ public class WorkModeSwitch extends Button implements Insettable, View.OnClickLi
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (Utilities.ATLEAST_P) {
|
||||
if (Utilities.ATLEAST_P && mWorkTabVisible) {
|
||||
setEnabled(false);
|
||||
Launcher.fromContext(getContext()).getStatsLogManager().logger().log(
|
||||
LAUNCHER_TURN_OFF_WORK_APPS_TAP);
|
||||
@@ -137,7 +137,7 @@ public class WorkModeSwitch extends Button implements Insettable, View.OnClickLi
|
||||
|
||||
@Override
|
||||
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
|
||||
if (Utilities.ATLEAST_R) {
|
||||
if (Utilities.ATLEAST_R && mWorkTabVisible) {
|
||||
setTranslationY(0);
|
||||
if (insets.isVisible(WindowInsets.Type.ime())) {
|
||||
Insets keyboardInsets = insets.getInsets(WindowInsets.Type.ime());
|
||||
|
||||
@@ -18,8 +18,10 @@ package com.android.launcher3.allapps.search;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_FOCUSED_ITEM_SELECTED_WITH_IME;
|
||||
|
||||
import android.text.Editable;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextWatcher;
|
||||
import android.text.style.SuggestionSpan;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.View.OnFocusChangeListener;
|
||||
@@ -47,6 +49,7 @@ public class AllAppsSearchBarController
|
||||
protected SearchCallback<AdapterItem> mCallback;
|
||||
protected ExtendedEditText mInput;
|
||||
protected String mQuery;
|
||||
private String[] mTextConversions;
|
||||
|
||||
protected SearchAlgorithm<AdapterItem> mSearchAlgorithm;
|
||||
|
||||
@@ -78,7 +81,20 @@ public class AllAppsSearchBarController
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
// Do nothing
|
||||
mTextConversions = extractTextConversions(s);
|
||||
}
|
||||
|
||||
private static String[] extractTextConversions(CharSequence text) {
|
||||
if (text instanceof SpannableStringBuilder) {
|
||||
SpannableStringBuilder spanned = (SpannableStringBuilder) text;
|
||||
SuggestionSpan[] suggestionSpans =
|
||||
spanned.getSpans(0, text.length(), SuggestionSpan.class);
|
||||
if (suggestionSpans != null && suggestionSpans.length > 0) {
|
||||
spanned.removeSpan(suggestionSpans[0]);
|
||||
return suggestionSpans[0].getSuggestions();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -89,7 +105,7 @@ public class AllAppsSearchBarController
|
||||
mCallback.clearSearchResult();
|
||||
} else {
|
||||
mSearchAlgorithm.cancel(false);
|
||||
mSearchAlgorithm.doSearch(mQuery, mCallback);
|
||||
mSearchAlgorithm.doSearch(mQuery, mTextConversions, mCallback);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,4 +170,4 @@ public class AllAppsSearchBarController
|
||||
public boolean isSearchFieldFocused() {
|
||||
return mInput.isFocused();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ public final class FeatureFlags {
|
||||
+ "Ignored if ENABLE_SMARTSPACE_UNIVERSAL is enabled.");
|
||||
|
||||
public static final BooleanFlag ENABLE_SMARTSPACE_FEEDBACK = getDebugFlag(
|
||||
"ENABLE_SMARTSPACE_FEEDBACK", true,
|
||||
"ENABLE_SMARTSPACE_FEEDBACK", false,
|
||||
"Adds a menu option to send feedback for Enhanced Smartspace.");
|
||||
|
||||
public static final BooleanFlag ENABLE_SMARTSPACE_DISMISS = getDebugFlag(
|
||||
@@ -254,6 +254,10 @@ public final class FeatureFlags {
|
||||
"ENABLE_WALLPAPER_SCRIM", false,
|
||||
"Enables scrim over wallpaper for text protection.");
|
||||
|
||||
public static final BooleanFlag WIDGETS_IN_LAUNCHER_PREVIEW = getDebugFlag(
|
||||
"WIDGETS_IN_LAUNCHER_PREVIEW", true,
|
||||
"Enables widgets in Launcher preview for the Wallpaper app.");
|
||||
|
||||
public static void initialize(Context context) {
|
||||
synchronized (sDebugFlags) {
|
||||
for (DebugFlag flag : sDebugFlags) {
|
||||
|
||||
@@ -29,6 +29,7 @@ import android.annotation.TargetApi;
|
||||
import android.app.Fragment;
|
||||
import android.app.WallpaperColors;
|
||||
import android.app.WallpaperManager;
|
||||
import android.appwidget.AppWidgetHost;
|
||||
import android.appwidget.AppWidgetHostView;
|
||||
import android.appwidget.AppWidgetProviderInfo;
|
||||
import android.content.Context;
|
||||
@@ -87,8 +88,11 @@ import com.android.launcher3.util.IntArray;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
import com.android.launcher3.views.BaseDragLayer;
|
||||
import com.android.launcher3.widget.BaseLauncherAppWidgetHostView;
|
||||
import com.android.launcher3.widget.LauncherAppWidgetHost;
|
||||
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
|
||||
import com.android.launcher3.widget.LocalColorExtractor;
|
||||
import com.android.launcher3.widget.NavigableAppWidgetHostView;
|
||||
import com.android.launcher3.widget.custom.CustomWidgetManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -207,6 +211,7 @@ public class LauncherPreviewRenderer extends ContextWrapper
|
||||
private final Hotseat mHotseat;
|
||||
private final CellLayout mWorkspace;
|
||||
private final SparseIntArray mWallpaperColorResources;
|
||||
private final AppWidgetHost mAppWidgetHost;
|
||||
|
||||
public LauncherPreviewRenderer(Context context,
|
||||
InvariantDeviceProfile idp,
|
||||
@@ -273,6 +278,9 @@ public class LauncherPreviewRenderer extends ContextWrapper
|
||||
} else {
|
||||
mWallpaperColorResources = null;
|
||||
}
|
||||
mAppWidgetHost = FeatureFlags.WIDGETS_IN_LAUNCHER_PREVIEW.get()
|
||||
? new LauncherPreviewAppWidgetHost(context)
|
||||
: null;
|
||||
}
|
||||
|
||||
/** Populate preview and render it. */
|
||||
@@ -372,9 +380,20 @@ public class LauncherPreviewRenderer extends ContextWrapper
|
||||
|
||||
private void inflateAndAddWidgets(
|
||||
LauncherAppWidgetInfo info, LauncherAppWidgetProviderInfo providerInfo) {
|
||||
AppWidgetHostView view = new AppWidgetHostView(mContext);
|
||||
view.setAppWidget(-1, providerInfo);
|
||||
view.updateAppWidget(null);
|
||||
AppWidgetHostView view;
|
||||
if (FeatureFlags.WIDGETS_IN_LAUNCHER_PREVIEW.get()) {
|
||||
view = mAppWidgetHost.createView(mContext, info.appWidgetId, providerInfo);
|
||||
} else {
|
||||
view = new NavigableAppWidgetHostView(this) {
|
||||
@Override
|
||||
protected boolean shouldAllowDirectClick() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
view.setAppWidget(-1, providerInfo);
|
||||
view.updateAppWidget(null);
|
||||
}
|
||||
|
||||
view.setTag(info);
|
||||
|
||||
if (mWallpaperColorResources != null) {
|
||||
@@ -504,4 +523,31 @@ public class LauncherPreviewRenderer extends ContextWrapper
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class LauncherPreviewAppWidgetHost extends AppWidgetHost {
|
||||
|
||||
private LauncherPreviewAppWidgetHost(Context context) {
|
||||
super(context, LauncherAppWidgetHost.APPWIDGET_HOST_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AppWidgetHostView onCreateView(
|
||||
Context context,
|
||||
int appWidgetId,
|
||||
AppWidgetProviderInfo appWidget) {
|
||||
return new LauncherPreviewAppWidgetHostView(LauncherPreviewRenderer.this);
|
||||
}
|
||||
}
|
||||
|
||||
private static class LauncherPreviewAppWidgetHostView extends BaseLauncherAppWidgetHostView {
|
||||
|
||||
private LauncherPreviewAppWidgetHostView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldAllowDirectClick() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import android.content.pm.PackageManager;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.model.data.AppInfo;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.model.data.ItemInfoWithIcon;
|
||||
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
|
||||
import com.android.launcher3.pm.PackageInstallInfo;
|
||||
import com.android.launcher3.util.InstantAppResolver;
|
||||
@@ -73,13 +72,7 @@ public class PackageInstallStateChangedTask extends BaseModelUpdateTask {
|
||||
dataModel.forAllWorkspaceItemInfos(mInstallInfo.user, si -> {
|
||||
if (si.hasPromiseIconUi()
|
||||
&& mInstallInfo.packageName.equals(si.getTargetPackage())) {
|
||||
int installProgress = mInstallInfo.progress;
|
||||
|
||||
si.setProgressLevel(installProgress, PackageInstallInfo.STATUS_INSTALLING);
|
||||
if (mInstallInfo.state == PackageInstallInfo.STATUS_FAILED) {
|
||||
// Mark this info as broken.
|
||||
si.runtimeStatusFlags &= ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;
|
||||
}
|
||||
si.setProgressLevel(mInstallInfo);
|
||||
updates.add(si);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -24,6 +24,7 @@ import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.icons.BitmapInfo;
|
||||
import com.android.launcher3.icons.FastBitmapDrawable;
|
||||
import com.android.launcher3.logging.FileLog;
|
||||
import com.android.launcher3.pm.PackageInstallInfo;
|
||||
import com.android.launcher3.util.PackageManagerHelper;
|
||||
|
||||
@@ -179,6 +180,12 @@ public abstract class ItemInfoWithIcon extends ItemInfo {
|
||||
*/
|
||||
public void setProgressLevel(PackageInstallInfo installInfo) {
|
||||
setProgressLevel(installInfo.progress, installInfo.state);
|
||||
|
||||
if (installInfo.state == PackageInstallInfo.STATUS_FAILED) {
|
||||
FileLog.d(TAG,
|
||||
"Icon info: " + this + " marked broken with install info: " + installInfo,
|
||||
new Exception());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.notification;
|
||||
|
||||
import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
|
||||
import static com.android.launcher3.touch.SingleAxisSwipeDetector.HORIZONTAL;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.FloatProperty;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.anim.AnimationSuccessListener;
|
||||
import com.android.launcher3.popup.PopupContainerWithArrow;
|
||||
import com.android.launcher3.touch.BaseSwipeDetector;
|
||||
import com.android.launcher3.touch.OverScroll;
|
||||
import com.android.launcher3.touch.SingleAxisSwipeDetector;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Class to manage the notification UI in a {@link PopupContainerWithArrow}.
|
||||
*
|
||||
* - Has two {@link NotificationMainView} that represent the top two notifications
|
||||
* - Handles dismissing a notification
|
||||
*/
|
||||
public class NotificationContainer extends FrameLayout implements SingleAxisSwipeDetector.Listener {
|
||||
|
||||
private static final FloatProperty<NotificationContainer> DRAG_TRANSLATION_X =
|
||||
new FloatProperty<NotificationContainer>("notificationProgress") {
|
||||
@Override
|
||||
public void setValue(NotificationContainer view, float transX) {
|
||||
view.setDragTranslationX(transX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(NotificationContainer view) {
|
||||
return view.mDragTranslationX;
|
||||
}
|
||||
};
|
||||
|
||||
private static final Rect sTempRect = new Rect();
|
||||
|
||||
private final SingleAxisSwipeDetector mSwipeDetector;
|
||||
private final List<NotificationInfo> mNotificationInfos = new ArrayList<>();
|
||||
private boolean mIgnoreTouch = false;
|
||||
|
||||
private final ObjectAnimator mContentTranslateAnimator;
|
||||
private float mDragTranslationX = 0;
|
||||
|
||||
private final NotificationMainView mPrimaryView;
|
||||
private final NotificationMainView mSecondaryView;
|
||||
private PopupContainerWithArrow mPopupContainer;
|
||||
|
||||
public NotificationContainer(Context context) {
|
||||
this(context, null, 0);
|
||||
}
|
||||
|
||||
public NotificationContainer(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public NotificationContainer(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
mSwipeDetector = new SingleAxisSwipeDetector(getContext(), this, HORIZONTAL);
|
||||
mSwipeDetector.setDetectableScrollConditions(SingleAxisSwipeDetector.DIRECTION_BOTH, false);
|
||||
mContentTranslateAnimator = ObjectAnimator.ofFloat(this, DRAG_TRANSLATION_X, 0);
|
||||
|
||||
mPrimaryView = (NotificationMainView) View.inflate(getContext(),
|
||||
R.layout.notification_content, null);
|
||||
mSecondaryView = (NotificationMainView) View.inflate(getContext(),
|
||||
R.layout.notification_content, null);
|
||||
mSecondaryView.setAlpha(0);
|
||||
|
||||
addView(mSecondaryView);
|
||||
addView(mPrimaryView);
|
||||
|
||||
}
|
||||
|
||||
public void setPopupView(PopupContainerWithArrow popupView) {
|
||||
mPopupContainer = popupView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if we should intercept the swipe.
|
||||
*/
|
||||
public boolean onInterceptSwipeEvent(MotionEvent ev) {
|
||||
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
sTempRect.set(getLeft(), getTop(), getRight(), getBottom());
|
||||
mIgnoreTouch = !sTempRect.contains((int) ev.getX(), (int) ev.getY());
|
||||
if (!mIgnoreTouch) {
|
||||
mPopupContainer.getParent().requestDisallowInterceptTouchEvent(true);
|
||||
}
|
||||
}
|
||||
if (mIgnoreTouch) {
|
||||
return false;
|
||||
}
|
||||
if (mPrimaryView.getNotificationInfo() == null) {
|
||||
// The notification hasn't been populated yet.
|
||||
return false;
|
||||
}
|
||||
|
||||
mSwipeDetector.onTouchEvent(ev);
|
||||
return mSwipeDetector.isDraggingOrSettling();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true when we should handle the swipe.
|
||||
*/
|
||||
public boolean onSwipeEvent(MotionEvent ev) {
|
||||
if (mIgnoreTouch) {
|
||||
return false;
|
||||
}
|
||||
if (mPrimaryView.getNotificationInfo() == null) {
|
||||
// The notification hasn't been populated yet.
|
||||
return false;
|
||||
}
|
||||
return mSwipeDetector.onTouchEvent(ev);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the list of @param notificationInfos to this container.
|
||||
*/
|
||||
public void applyNotificationInfos(final List<NotificationInfo> notificationInfos) {
|
||||
mNotificationInfos.clear();
|
||||
if (notificationInfos.isEmpty()) {
|
||||
mPrimaryView.applyNotificationInfo(null);
|
||||
mSecondaryView.applyNotificationInfo(null);
|
||||
return;
|
||||
}
|
||||
mNotificationInfos.addAll(notificationInfos);
|
||||
|
||||
NotificationInfo mainNotification = notificationInfos.get(0);
|
||||
mPrimaryView.applyNotificationInfo(mainNotification);
|
||||
mSecondaryView.applyNotificationInfo(notificationInfos.size() > 1
|
||||
? notificationInfos.get(1)
|
||||
: null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trims the notifications.
|
||||
* @param notificationKeys List of all valid notification keys.
|
||||
*/
|
||||
public void trimNotifications(final List<String> notificationKeys) {
|
||||
Iterator<NotificationInfo> iterator = mNotificationInfos.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
if (!notificationKeys.contains(iterator.next().notificationKey)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
NotificationInfo primaryInfo = mNotificationInfos.size() > 0
|
||||
? mNotificationInfos.get(0)
|
||||
: null;
|
||||
NotificationInfo secondaryInfo = mNotificationInfos.size() > 1
|
||||
? mNotificationInfos.get(1)
|
||||
: null;
|
||||
|
||||
mPrimaryView.applyNotificationInfo(primaryInfo);
|
||||
mSecondaryView.applyNotificationInfo(secondaryInfo);
|
||||
|
||||
mPrimaryView.onPrimaryDrag(0);
|
||||
mSecondaryView.onSecondaryDrag(0);
|
||||
}
|
||||
|
||||
private void setDragTranslationX(float translationX) {
|
||||
mDragTranslationX = translationX;
|
||||
|
||||
float progress = translationX / getWidth();
|
||||
mPrimaryView.onPrimaryDrag(progress);
|
||||
if (mSecondaryView.getNotificationInfo() == null) {
|
||||
mSecondaryView.setAlpha(0f);
|
||||
} else {
|
||||
mSecondaryView.onSecondaryDrag(progress);
|
||||
}
|
||||
}
|
||||
|
||||
// SingleAxisSwipeDetector.Listener's
|
||||
@Override
|
||||
public void onDragStart(boolean start, float startDisplacement) {
|
||||
mPopupContainer.showArrow(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDrag(float displacement) {
|
||||
if (!mPrimaryView.canChildBeDismissed()) {
|
||||
displacement = OverScroll.dampedScroll(displacement, getWidth());
|
||||
}
|
||||
|
||||
float progress = displacement / getWidth();
|
||||
mPrimaryView.onPrimaryDrag(progress);
|
||||
if (mSecondaryView.getNotificationInfo() == null) {
|
||||
mSecondaryView.setAlpha(0f);
|
||||
} else {
|
||||
mSecondaryView.onSecondaryDrag(progress);
|
||||
}
|
||||
mContentTranslateAnimator.cancel();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDragEnd(float velocity) {
|
||||
final boolean willExit;
|
||||
final float endTranslation;
|
||||
final float startTranslation = mPrimaryView.getTranslationX();
|
||||
final float width = getWidth();
|
||||
|
||||
if (!mPrimaryView.canChildBeDismissed()) {
|
||||
willExit = false;
|
||||
endTranslation = 0;
|
||||
} else if (mSwipeDetector.isFling(velocity)) {
|
||||
willExit = true;
|
||||
endTranslation = velocity < 0 ? -width : width;
|
||||
} else if (Math.abs(startTranslation) > width / 2f) {
|
||||
willExit = true;
|
||||
endTranslation = (startTranslation < 0 ? -width : width);
|
||||
} else {
|
||||
willExit = false;
|
||||
endTranslation = 0;
|
||||
}
|
||||
|
||||
long duration = BaseSwipeDetector.calculateDuration(velocity,
|
||||
(endTranslation - startTranslation) / width);
|
||||
|
||||
mContentTranslateAnimator.removeAllListeners();
|
||||
mContentTranslateAnimator.setDuration(duration)
|
||||
.setInterpolator(scrollInterpolatorForVelocity(velocity));
|
||||
mContentTranslateAnimator.setFloatValues(startTranslation, endTranslation);
|
||||
|
||||
NotificationMainView current = mPrimaryView;
|
||||
mContentTranslateAnimator.addListener(new AnimationSuccessListener() {
|
||||
@Override
|
||||
public void onAnimationSuccess(Animator animator) {
|
||||
mSwipeDetector.finishedScrolling();
|
||||
if (willExit) {
|
||||
current.onChildDismissed();
|
||||
}
|
||||
mPopupContainer.showArrow(true);
|
||||
}
|
||||
});
|
||||
mContentTranslateAnimator.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Animates the background color to a new color.
|
||||
* @param color The color to change to.
|
||||
* @param animatorSetOut The AnimatorSet where we add the color animator to.
|
||||
*/
|
||||
public void updateBackgroundColor(int color, AnimatorSet animatorSetOut) {
|
||||
mPrimaryView.updateBackgroundColor(color, animatorSetOut);
|
||||
mSecondaryView.updateBackgroundColor(color, animatorSetOut);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the header with a new @param notificationCount.
|
||||
*/
|
||||
public void updateHeader(int notificationCount) {
|
||||
mPrimaryView.updateHeader(notificationCount);
|
||||
mSecondaryView.updateHeader(notificationCount - 1);
|
||||
}
|
||||
}
|
||||
@@ -1,179 +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.notification;
|
||||
|
||||
import android.animation.AnimatorSet;
|
||||
import android.content.Context;
|
||||
import android.graphics.Outline;
|
||||
import android.graphics.Rect;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewGroup.MarginLayoutParams;
|
||||
import android.view.ViewOutlineProvider;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.popup.PopupContainerWithArrow;
|
||||
import com.android.launcher3.util.Themes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Utility class to manage notification UI
|
||||
*/
|
||||
public class NotificationItemView {
|
||||
|
||||
private static final Rect sTempRect = new Rect();
|
||||
|
||||
private final Context mContext;
|
||||
private final PopupContainerWithArrow mPopupContainer;
|
||||
private final ViewGroup mRootView;
|
||||
|
||||
private final TextView mHeaderCount;
|
||||
private final NotificationMainView mMainView;
|
||||
|
||||
private final View mHeader;
|
||||
|
||||
private View mGutter;
|
||||
|
||||
private boolean mIgnoreTouch = false;
|
||||
private List<NotificationInfo> mNotificationInfos = new ArrayList<>();
|
||||
|
||||
public NotificationItemView(PopupContainerWithArrow container, ViewGroup rootView) {
|
||||
mPopupContainer = container;
|
||||
mRootView = rootView;
|
||||
mContext = container.getContext();
|
||||
|
||||
mHeaderCount = container.findViewById(R.id.notification_count);
|
||||
mMainView = container.findViewById(R.id.main_view);
|
||||
|
||||
mHeader = container.findViewById(R.id.header);
|
||||
|
||||
float radius = Themes.getDialogCornerRadius(mContext);
|
||||
rootView.setClipToOutline(true);
|
||||
rootView.setOutlineProvider(new ViewOutlineProvider() {
|
||||
@Override
|
||||
public void getOutline(View view, Outline outline) {
|
||||
outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), radius);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Animates the background color to a new color.
|
||||
* @param color The color to change to.
|
||||
* @param animatorSetOut The AnimatorSet where we add the color animator to.
|
||||
*/
|
||||
public void updateBackgroundColor(int color, AnimatorSet animatorSetOut) {
|
||||
mMainView.updateBackgroundColor(color, animatorSetOut);
|
||||
}
|
||||
|
||||
public void addGutter() {
|
||||
if (mGutter == null) {
|
||||
mGutter = mPopupContainer.inflateAndAdd(R.layout.notification_gutter, mRootView);
|
||||
}
|
||||
}
|
||||
|
||||
public void inverseGutterMargin() {
|
||||
MarginLayoutParams lp = (MarginLayoutParams) mGutter.getLayoutParams();
|
||||
int top = lp.topMargin;
|
||||
lp.topMargin = lp.bottomMargin;
|
||||
lp.bottomMargin = top;
|
||||
}
|
||||
|
||||
public void removeAllViews() {
|
||||
mRootView.removeView(mMainView);
|
||||
mRootView.removeView(mHeader);
|
||||
if (mGutter != null) {
|
||||
mRootView.removeView(mGutter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the header text.
|
||||
* @param notificationCount The number of notifications.
|
||||
*/
|
||||
public void updateHeader(int notificationCount) {
|
||||
final String text;
|
||||
final int visibility;
|
||||
if (notificationCount <= 1) {
|
||||
text = "";
|
||||
visibility = View.INVISIBLE;
|
||||
} else {
|
||||
text = String.valueOf(notificationCount);
|
||||
visibility = View.VISIBLE;
|
||||
|
||||
}
|
||||
mHeaderCount.setText(text);
|
||||
mHeaderCount.setVisibility(visibility);
|
||||
}
|
||||
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
sTempRect.set(mRootView.getLeft(), mRootView.getTop(),
|
||||
mRootView.getRight(), mRootView.getBottom());
|
||||
mIgnoreTouch = !sTempRect.contains((int) ev.getX(), (int) ev.getY());
|
||||
if (!mIgnoreTouch) {
|
||||
mPopupContainer.getParent().requestDisallowInterceptTouchEvent(true);
|
||||
}
|
||||
}
|
||||
if (mIgnoreTouch) {
|
||||
return false;
|
||||
}
|
||||
if (mMainView.getNotificationInfo() == null) {
|
||||
// The notification hasn't been populated yet.
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void applyNotificationInfos(final List<NotificationInfo> notificationInfos) {
|
||||
mNotificationInfos.clear();
|
||||
if (notificationInfos.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
mNotificationInfos.addAll(notificationInfos);
|
||||
|
||||
NotificationInfo mainNotification = notificationInfos.get(0);
|
||||
mMainView.applyNotificationInfo(mainNotification, false);
|
||||
}
|
||||
|
||||
public void trimNotifications(final List<String> notificationKeys) {
|
||||
NotificationInfo currentMainNotificationInfo = mMainView.getNotificationInfo();
|
||||
boolean shouldUpdateMainNotification = !notificationKeys.contains(
|
||||
currentMainNotificationInfo.notificationKey);
|
||||
|
||||
if (shouldUpdateMainNotification) {
|
||||
int size = notificationKeys.size();
|
||||
NotificationInfo nextNotification = null;
|
||||
// We get the latest notification by finding the notification after the one that was
|
||||
// just dismissed.
|
||||
for (int i = 0; i < size; ++i) {
|
||||
if (currentMainNotificationInfo == mNotificationInfos.get(i) && i + 1 < size) {
|
||||
nextNotification = mNotificationInfos.get(i + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (nextNotification != null) {
|
||||
mMainView.applyNotificationInfo(nextNotification, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,62 +16,70 @@
|
||||
|
||||
package com.android.launcher3.notification;
|
||||
|
||||
import static com.android.launcher3.Utilities.mapToRange;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NOTIFICATION_DISMISSED;
|
||||
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.Outline;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.GradientDrawable;
|
||||
import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.FloatProperty;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.view.ViewOutlineProvider;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.touch.SingleAxisSwipeDetector;
|
||||
import com.android.launcher3.util.Themes;
|
||||
|
||||
/**
|
||||
* A {@link android.widget.FrameLayout} that contains a single notification,
|
||||
* e.g. icon + title + text.
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.N)
|
||||
public class NotificationMainView extends FrameLayout {
|
||||
|
||||
private static final FloatProperty<NotificationMainView> CONTENT_TRANSLATION =
|
||||
new FloatProperty<NotificationMainView>("contentTranslation") {
|
||||
@Override
|
||||
public void setValue(NotificationMainView view, float v) {
|
||||
view.setContentTranslation(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(NotificationMainView view) {
|
||||
return view.mTextAndBackground.getTranslationX();
|
||||
}
|
||||
};
|
||||
public class NotificationMainView extends LinearLayout {
|
||||
|
||||
// This is used only to track the notification view, so that it can be properly logged.
|
||||
public static final ItemInfo NOTIFICATION_ITEM_INFO = new ItemInfo();
|
||||
|
||||
// Value when the primary notification main view will be gone (zero alpha).
|
||||
private static final float PRIMARY_GONE_PROGRESS = 0.7f;
|
||||
private static final float PRIMARY_MIN_PROGRESS = 0.40f;
|
||||
private static final float PRIMARY_MAX_PROGRESS = 0.60f;
|
||||
private static final float SECONDARY_MIN_PROGRESS = 0.30f;
|
||||
private static final float SECONDARY_MAX_PROGRESS = 0.50f;
|
||||
private static final float SECONDARY_CONTENT_MAX_PROGRESS = 0.6f;
|
||||
|
||||
private NotificationInfo mNotificationInfo;
|
||||
private ViewGroup mTextAndBackground;
|
||||
private int mBackgroundColor;
|
||||
private TextView mTitleView;
|
||||
private TextView mTextView;
|
||||
private View mIconView;
|
||||
|
||||
private SingleAxisSwipeDetector mSwipeDetector;
|
||||
private View mHeader;
|
||||
private View mMainView;
|
||||
|
||||
private final ColorDrawable mColorDrawable;
|
||||
private TextView mHeaderCount;
|
||||
private final Rect mOutline = new Rect();
|
||||
|
||||
// Space between notifications during swipe
|
||||
private final int mNotificationSpace;
|
||||
private final int mMaxTransX;
|
||||
private final int mMaxElevation;
|
||||
|
||||
private final GradientDrawable mBackground;
|
||||
|
||||
public NotificationMainView(Context context) {
|
||||
this(context, null, 0);
|
||||
@@ -82,28 +90,77 @@ public class NotificationMainView extends FrameLayout {
|
||||
}
|
||||
|
||||
public NotificationMainView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
this(context, attrs, defStyle, 0);
|
||||
}
|
||||
|
||||
mColorDrawable = new ColorDrawable(Color.TRANSPARENT);
|
||||
public NotificationMainView(Context context, AttributeSet attrs, int defStyle, int defStylRes) {
|
||||
super(context, attrs, defStyle, defStylRes);
|
||||
|
||||
float outlineRadius = Themes.getDialogCornerRadius(context);
|
||||
|
||||
mBackground = new GradientDrawable();
|
||||
mBackground.setColor(Themes.getAttrColor(context, R.attr.popupColorPrimary));
|
||||
mBackground.setCornerRadius(outlineRadius);
|
||||
setBackground(mBackground);
|
||||
|
||||
mMaxElevation = getResources().getDimensionPixelSize(R.dimen.deep_shortcuts_elevation);
|
||||
setElevation(mMaxElevation);
|
||||
|
||||
mMaxTransX = getResources().getDimensionPixelSize(R.dimen.notification_max_trans);
|
||||
mNotificationSpace = getResources().getDimensionPixelSize(R.dimen.notification_space);
|
||||
|
||||
setClipToOutline(true);
|
||||
setOutlineProvider(new ViewOutlineProvider() {
|
||||
@Override
|
||||
public void getOutline(View view, Outline outline) {
|
||||
outline.setRoundRect(mOutline, outlineRadius);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the header text.
|
||||
* @param notificationCount The number of notifications.
|
||||
*/
|
||||
public void updateHeader(int notificationCount) {
|
||||
final String text;
|
||||
final int visibility;
|
||||
if (notificationCount <= 1) {
|
||||
text = "";
|
||||
visibility = View.INVISIBLE;
|
||||
} else {
|
||||
text = String.valueOf(notificationCount);
|
||||
visibility = View.VISIBLE;
|
||||
|
||||
}
|
||||
mHeaderCount.setText(text);
|
||||
mHeaderCount.setVisibility(visibility);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
|
||||
mTextAndBackground = findViewById(R.id.text_and_background);
|
||||
mTitleView = mTextAndBackground.findViewById(R.id.title);
|
||||
mTextView = mTextAndBackground.findViewById(R.id.text);
|
||||
ViewGroup textAndBackground = findViewById(R.id.text_and_background);
|
||||
mTitleView = textAndBackground.findViewById(R.id.title);
|
||||
mTextView = textAndBackground.findViewById(R.id.text);
|
||||
mIconView = findViewById(R.id.popup_item_icon);
|
||||
mHeaderCount = findViewById(R.id.notification_count);
|
||||
|
||||
ColorDrawable colorBackground = (ColorDrawable) mTextAndBackground.getBackground();
|
||||
updateBackgroundColor(colorBackground.getColor());
|
||||
mHeader = findViewById(R.id.header);
|
||||
mMainView = findViewById(R.id.main_view);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
mOutline.set(0, 0, getWidth(), getHeight());
|
||||
invalidateOutline();
|
||||
}
|
||||
|
||||
private void updateBackgroundColor(int color) {
|
||||
mBackgroundColor = color;
|
||||
mColorDrawable.setColor(color);
|
||||
mTextAndBackground.setBackground(mColorDrawable);
|
||||
mBackground.setColor(color);
|
||||
if (mNotificationInfo != null) {
|
||||
mIconView.setBackground(mNotificationInfo.getIconForBackground(getContext(),
|
||||
mBackgroundColor));
|
||||
@@ -128,8 +185,11 @@ public class NotificationMainView extends FrameLayout {
|
||||
/**
|
||||
* Sets the content of this view, animating it after a new icon shifts up if necessary.
|
||||
*/
|
||||
public void applyNotificationInfo(NotificationInfo mainNotification, boolean animate) {
|
||||
mNotificationInfo = mainNotification;
|
||||
public void applyNotificationInfo(NotificationInfo notificationInfo) {
|
||||
mNotificationInfo = notificationInfo;
|
||||
if (notificationInfo == null) {
|
||||
return;
|
||||
}
|
||||
NotificationListener listener = NotificationListener.getInstanceIfConnected();
|
||||
if (listener != null) {
|
||||
listener.setNotificationsShown(new String[] {mNotificationInfo.notificationKey});
|
||||
@@ -149,25 +209,112 @@ public class NotificationMainView extends FrameLayout {
|
||||
if (mNotificationInfo.intent != null) {
|
||||
setOnClickListener(mNotificationInfo);
|
||||
}
|
||||
setContentTranslation(0);
|
||||
|
||||
// Add a stub ItemInfo so that logging populates the correct container and item types
|
||||
// instead of DEFAULT_CONTAINERTYPE and DEFAULT_ITEMTYPE, respectively.
|
||||
setTag(NOTIFICATION_ITEM_INFO);
|
||||
if (animate) {
|
||||
ObjectAnimator.ofFloat(mTextAndBackground, ALPHA, 0, 1).setDuration(150).start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the alpha of only the child views.
|
||||
*/
|
||||
public void setContentAlpha(float alpha) {
|
||||
mHeader.setAlpha(alpha);
|
||||
mMainView.setAlpha(alpha);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the translation of only the child views.
|
||||
*/
|
||||
public void setContentTranslationX(float transX) {
|
||||
mHeader.setTranslationX(transX);
|
||||
mMainView.setTranslationX(transX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the alpha, content alpha, and elevation of this view.
|
||||
*
|
||||
* @param progress Range from [0, 1] or [-1, 0]
|
||||
* When 0: Full alpha
|
||||
* When 1/-1: zero alpha
|
||||
*/
|
||||
public void onPrimaryDrag(float progress) {
|
||||
float absProgress = Math.abs(progress);
|
||||
final int width = getWidth();
|
||||
|
||||
float min = PRIMARY_MIN_PROGRESS;
|
||||
float max = PRIMARY_MAX_PROGRESS;
|
||||
|
||||
if (absProgress < min) {
|
||||
setAlpha(1f);
|
||||
setContentAlpha(1);
|
||||
setElevation(mMaxElevation);
|
||||
} else if (absProgress < max) {
|
||||
setAlpha(1f);
|
||||
setContentAlpha(mapToRange(absProgress, min, max, 1f, 0f, LINEAR));
|
||||
setElevation(Utilities.mapToRange(absProgress, min, max, mMaxElevation, 0, LINEAR));
|
||||
} else {
|
||||
setAlpha(mapToRange(absProgress, max, PRIMARY_GONE_PROGRESS, 1f, 0f, LINEAR));
|
||||
setContentAlpha(0f);
|
||||
setElevation(0f);
|
||||
}
|
||||
|
||||
setTranslationX(width * progress);
|
||||
}
|
||||
|
||||
public void setContentTranslation(float translation) {
|
||||
mTextAndBackground.setTranslationX(translation);
|
||||
mIconView.setTranslationX(translation);
|
||||
/**
|
||||
* Updates the alpha, content alpha, elevation, and clipping of this view.
|
||||
* @param progress Range from [0, 1] or [-1, 0]
|
||||
* When 0: Smallest clipping, zero alpha
|
||||
* When 1/-1: Full clip, full alpha
|
||||
*/
|
||||
public void onSecondaryDrag(float progress) {
|
||||
final float absProgress = Math.abs(progress);
|
||||
|
||||
float min = SECONDARY_MIN_PROGRESS;
|
||||
float max = SECONDARY_MAX_PROGRESS;
|
||||
float contentMax = SECONDARY_CONTENT_MAX_PROGRESS;
|
||||
|
||||
if (absProgress < min) {
|
||||
setAlpha(0f);
|
||||
setContentAlpha(0);
|
||||
setElevation(0f);
|
||||
} else if (absProgress < max) {
|
||||
setAlpha(mapToRange(absProgress, min, max, 0, 1f, LINEAR));
|
||||
setContentAlpha(0f);
|
||||
setElevation(0f);
|
||||
} else {
|
||||
setAlpha(1f);
|
||||
setContentAlpha(absProgress > contentMax
|
||||
? 1f
|
||||
: mapToRange(absProgress, max, contentMax, 0, 1f, LINEAR));
|
||||
setElevation(Utilities.mapToRange(absProgress, max, 1, 0, mMaxElevation, LINEAR));
|
||||
}
|
||||
|
||||
final int width = getWidth();
|
||||
int crop = (int) (width * absProgress);
|
||||
int space = (int) (absProgress > PRIMARY_GONE_PROGRESS
|
||||
? mapToRange(absProgress, PRIMARY_GONE_PROGRESS, 1f, mNotificationSpace, 0, LINEAR)
|
||||
: mNotificationSpace);
|
||||
if (progress < 0) {
|
||||
mOutline.left = Math.max(0, getWidth() - crop + space);
|
||||
mOutline.right = getWidth();
|
||||
} else {
|
||||
mOutline.right = Math.min(getWidth(), crop - space);
|
||||
mOutline.left = 0;
|
||||
}
|
||||
|
||||
float contentTransX = mMaxTransX * (1f - absProgress);
|
||||
setContentTranslationX(progress < 0
|
||||
? contentTransX
|
||||
: -contentTransX);
|
||||
invalidateOutline();
|
||||
}
|
||||
|
||||
public NotificationInfo getNotificationInfo() {
|
||||
public @Nullable NotificationInfo getNotificationInfo() {
|
||||
return mNotificationInfo;
|
||||
}
|
||||
|
||||
|
||||
public boolean canChildBeDismissed() {
|
||||
return mNotificationInfo != null && mNotificationInfo.dismissable;
|
||||
}
|
||||
|
||||
@@ -57,4 +57,28 @@ public final class PackageInstallInfo {
|
||||
public static PackageInstallInfo fromState(int state, String packageName, UserHandle user) {
|
||||
return new PackageInstallInfo(packageName, state, 0 /* progress */, user);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + "(" + dumpProperties() + ")";
|
||||
}
|
||||
|
||||
private String dumpProperties() {
|
||||
return "componentName=" + componentName
|
||||
+ "packageName=" + packageName
|
||||
+ " state=" + stateToString()
|
||||
+ " progress=" + progress
|
||||
+ " user=" + user;
|
||||
}
|
||||
|
||||
private String stateToString() {
|
||||
switch (state) {
|
||||
case STATUS_INSTALLED : return "STATUS_INSTALLED";
|
||||
case STATUS_INSTALLING : return "STATUS_INSTALLING";
|
||||
case STATUS_INSTALLED_DOWNLOADING : return "STATUS_INSTALLED_DOWNLOADING";
|
||||
case STATUS_FAILED : return "STATUS_FAILED";
|
||||
default : return "INVALID STATE";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -487,6 +487,13 @@ public abstract class ArrowPopup<T extends StatefulActivity<LauncherState>>
|
||||
return getMeasuredWidth() - mArrowOffsetHorizontal - mArrowWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param show If true, shows arrow (when applicable), otherwise hides arrow.
|
||||
*/
|
||||
public void showArrow(boolean show) {
|
||||
mArrow.setVisibility(show && shouldAddArrow() ? VISIBLE : INVISIBLE);
|
||||
}
|
||||
|
||||
private void addArrow() {
|
||||
getPopupContainer().addView(mArrow);
|
||||
mArrow.setX(getX() + getArrowLeft());
|
||||
|
||||
@@ -58,8 +58,8 @@ import com.android.launcher3.dragndrop.DraggableView;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.model.data.ItemInfoWithIcon;
|
||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||
import com.android.launcher3.notification.NotificationContainer;
|
||||
import com.android.launcher3.notification.NotificationInfo;
|
||||
import com.android.launcher3.notification.NotificationItemView;
|
||||
import com.android.launcher3.notification.NotificationKeyData;
|
||||
import com.android.launcher3.popup.PopupDataProvider.PopupDataChangeListener;
|
||||
import com.android.launcher3.shortcuts.DeepShortcutView;
|
||||
@@ -92,9 +92,8 @@ public class PopupContainerWithArrow<T extends StatefulActivity<LauncherState>>
|
||||
private final int mStartDragThreshold;
|
||||
|
||||
private BubbleTextView mOriginalIcon;
|
||||
private NotificationItemView mNotificationItemView;
|
||||
private int mNumNotifications;
|
||||
private ViewGroup mNotificationContainer;
|
||||
private NotificationContainer mNotificationContainer;
|
||||
|
||||
private ViewGroup mWidgetContainer;
|
||||
|
||||
@@ -128,8 +127,8 @@ public class PopupContainerWithArrow<T extends StatefulActivity<LauncherState>>
|
||||
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
mInterceptTouchDown.set(ev.getX(), ev.getY());
|
||||
}
|
||||
if (mNotificationItemView != null
|
||||
&& mNotificationItemView.onInterceptTouchEvent(ev)) {
|
||||
if (mNotificationContainer != null
|
||||
&& mNotificationContainer.onInterceptSwipeEvent(ev)) {
|
||||
return true;
|
||||
}
|
||||
// Stop sending touch events to deep shortcut views if user moved beyond touch slop.
|
||||
@@ -137,6 +136,14 @@ public class PopupContainerWithArrow<T extends StatefulActivity<LauncherState>>
|
||||
> squaredTouchSlop(getContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
if (mNotificationContainer != null) {
|
||||
return mNotificationContainer.onSwipeEvent(ev) || super.onTouchEvent(ev);
|
||||
}
|
||||
return super.onTouchEvent(ev);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isOfType(int type) {
|
||||
return (type & TYPE_ACTION_POPUP) != 0;
|
||||
@@ -172,8 +179,8 @@ public class PopupContainerWithArrow<T extends StatefulActivity<LauncherState>>
|
||||
@Override
|
||||
protected void setChildColor(View view, int color, AnimatorSet animatorSetOut) {
|
||||
super.setChildColor(view, color, animatorSetOut);
|
||||
if (view.getId() == R.id.notification_container && mNotificationItemView != null) {
|
||||
mNotificationItemView.updateBackgroundColor(color, animatorSetOut);
|
||||
if (view.getId() == R.id.notification_container && mNotificationContainer != null) {
|
||||
mNotificationContainer.updateBackgroundColor(color, animatorSetOut);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,13 +239,6 @@ public class PopupContainerWithArrow<T extends StatefulActivity<LauncherState>>
|
||||
mNotificationContainer);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onInflationComplete(boolean isReversed) {
|
||||
if (isReversed && mNotificationItemView != null) {
|
||||
mNotificationItemView.inverseGutterMargin();
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.P)
|
||||
public void populateAndShow(final BubbleTextView originalIcon, int shortcutCount,
|
||||
final List<NotificationKeyData> notificationKeys, List<SystemShortcut> systemShortcuts) {
|
||||
@@ -261,9 +261,10 @@ public class PopupContainerWithArrow<T extends StatefulActivity<LauncherState>>
|
||||
if (mNotificationContainer == null) {
|
||||
mNotificationContainer = findViewById(R.id.notification_container);
|
||||
mNotificationContainer.setVisibility(VISIBLE);
|
||||
mNotificationContainer.setPopupView(this);
|
||||
} else {
|
||||
mNotificationContainer.setVisibility(GONE);
|
||||
}
|
||||
View.inflate(getContext(), R.layout.notification_content, mNotificationContainer);
|
||||
mNotificationItemView = new NotificationItemView(this, mNotificationContainer);
|
||||
updateNotificationHeader();
|
||||
}
|
||||
int viewsToFlip = getChildCount();
|
||||
@@ -274,10 +275,6 @@ public class PopupContainerWithArrow<T extends StatefulActivity<LauncherState>>
|
||||
if (hasDeepShortcuts) {
|
||||
mDeepShortcutContainer.setVisibility(View.VISIBLE);
|
||||
|
||||
if (mNotificationItemView != null) {
|
||||
mNotificationItemView.addGutter();
|
||||
}
|
||||
|
||||
for (int i = shortcutCount; i > 0; i--) {
|
||||
DeepShortcutView v = inflateAndAdd(R.layout.deep_shortcut, mDeepShortcutContainer);
|
||||
v.getLayoutParams().width = containerWidth;
|
||||
@@ -309,10 +306,6 @@ public class PopupContainerWithArrow<T extends StatefulActivity<LauncherState>>
|
||||
} else {
|
||||
mDeepShortcutContainer.setVisibility(View.GONE);
|
||||
if (!systemShortcuts.isEmpty()) {
|
||||
if (mNotificationItemView != null) {
|
||||
mNotificationItemView.addGutter();
|
||||
}
|
||||
|
||||
for (SystemShortcut shortcut : systemShortcuts) {
|
||||
initializeSystemShortcut(R.layout.system_shortcut, this, shortcut);
|
||||
}
|
||||
@@ -355,13 +348,13 @@ public class PopupContainerWithArrow<T extends StatefulActivity<LauncherState>>
|
||||
}
|
||||
|
||||
public void applyNotificationInfos(List<NotificationInfo> notificationInfos) {
|
||||
if (mNotificationItemView != null) {
|
||||
mNotificationItemView.applyNotificationInfos(notificationInfos);
|
||||
if (mNotificationContainer != null) {
|
||||
mNotificationContainer.applyNotificationInfos(notificationInfos);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateHiddenShortcuts() {
|
||||
int allowedCount = mNotificationItemView != null
|
||||
int allowedCount = mNotificationContainer != null
|
||||
? MAX_SHORTCUTS_IF_NOTIFICATIONS : MAX_SHORTCUTS;
|
||||
|
||||
int total = mShortcuts.size();
|
||||
@@ -447,8 +440,8 @@ public class PopupContainerWithArrow<T extends StatefulActivity<LauncherState>>
|
||||
private void updateNotificationHeader() {
|
||||
ItemInfoWithIcon itemInfo = (ItemInfoWithIcon) mOriginalIcon.getTag();
|
||||
DotInfo dotInfo = mLauncher.getDotInfoForItem(itemInfo);
|
||||
if (mNotificationItemView != null && dotInfo != null) {
|
||||
mNotificationItemView.updateHeader(dotInfo.getNotificationCount());
|
||||
if (mNotificationContainer != null && dotInfo != null) {
|
||||
mNotificationContainer.updateHeader(dotInfo.getNotificationCount());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -590,20 +583,18 @@ public class PopupContainerWithArrow<T extends StatefulActivity<LauncherState>>
|
||||
|
||||
@Override
|
||||
public void trimNotifications(Map<PackageUserKey, DotInfo> updatedDots) {
|
||||
if (mNotificationItemView == null) {
|
||||
if (mNotificationContainer == null) {
|
||||
return;
|
||||
}
|
||||
ItemInfo originalInfo = (ItemInfo) mOriginalIcon.getTag();
|
||||
DotInfo dotInfo = updatedDots.get(PackageUserKey.fromItemInfo(originalInfo));
|
||||
if (dotInfo == null || dotInfo.getNotificationKeys().size() == 0) {
|
||||
// No more notifications, remove the notification views and expand all shortcuts.
|
||||
mNotificationItemView.removeAllViews();
|
||||
mNotificationItemView = null;
|
||||
mNotificationContainer.setVisibility(GONE);
|
||||
updateHiddenShortcuts();
|
||||
assignMarginsAndBackgrounds(PopupContainerWithArrow.this);
|
||||
} else {
|
||||
mNotificationItemView.trimNotifications(
|
||||
mNotificationContainer.trimNotifications(
|
||||
NotificationKeyData.extractKeysOnly(dotInfo.getNotificationKeys()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,13 @@ public interface SearchAlgorithm<T> {
|
||||
*/
|
||||
void doSearch(String query, SearchCallback<T> callback);
|
||||
|
||||
/**
|
||||
* Performs search with {@code query} and the {@code suggestedQueries}/
|
||||
*/
|
||||
default void doSearch(String query, String[] suggestedQueries, SearchCallback<T> callback) {
|
||||
doSearch(query, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels any active request.
|
||||
*/
|
||||
|
||||
@@ -62,8 +62,9 @@ public class SettingsActivity extends FragmentActivity
|
||||
SharedPreferences.OnSharedPreferenceChangeListener{
|
||||
|
||||
/** List of fragments that can be hosted by this activity. */
|
||||
private static final List<String> VALID_PREFERENCE_FRAGMENTS = Collections.singletonList(
|
||||
DeveloperOptionsFragment.class.getName());
|
||||
private static final List<String> VALID_PREFERENCE_FRAGMENTS =
|
||||
!Utilities.IS_DEBUG_DEVICE ? Collections.emptyList()
|
||||
: Collections.singletonList(DeveloperOptionsFragment.class.getName());
|
||||
|
||||
private static final String DEVELOPER_OPTIONS_KEY = "pref_developer_options";
|
||||
private static final String FLAGS_PREFERENCE_KEY = "flag_toggler";
|
||||
|
||||
@@ -25,23 +25,27 @@ import android.graphics.drawable.ColorDrawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
|
||||
import com.android.launcher3.BaseActivity;
|
||||
import com.android.launcher3.Insettable;
|
||||
import com.android.launcher3.util.SystemUiController;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Simple scrim which draws a flat color
|
||||
*/
|
||||
public class ScrimView extends View implements Insettable {
|
||||
private static final float STATUS_BAR_COLOR_FORCE_UPDATE_THRESHOLD = 0.9f;
|
||||
|
||||
private final ArrayList<Runnable> mOpaquenessListeners = new ArrayList<>(1);
|
||||
private SystemUiController mSystemUiController;
|
||||
|
||||
private ScrimDrawingController mDrawingController;
|
||||
private int mBackgroundColor;
|
||||
private boolean mIsVisible = true;
|
||||
private boolean mLastDispatchedOpaqueness;
|
||||
|
||||
public ScrimView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
@@ -60,6 +64,7 @@ public class ScrimView extends View implements Insettable {
|
||||
@Override
|
||||
protected boolean onSetAlpha(int alpha) {
|
||||
updateSysUiColors();
|
||||
dispatchVisibilityListenersIfNeeded();
|
||||
return super.onSetAlpha(alpha);
|
||||
}
|
||||
|
||||
@@ -67,6 +72,7 @@ public class ScrimView extends View implements Insettable {
|
||||
public void setBackgroundColor(int color) {
|
||||
mBackgroundColor = color;
|
||||
updateSysUiColors();
|
||||
dispatchVisibilityListenersIfNeeded();
|
||||
super.setBackgroundColor(color);
|
||||
}
|
||||
|
||||
@@ -74,6 +80,7 @@ public class ScrimView extends View implements Insettable {
|
||||
public void onVisibilityAggregated(boolean isVisible) {
|
||||
super.onVisibilityAggregated(isVisible);
|
||||
mIsVisible = isVisible;
|
||||
dispatchVisibilityListenersIfNeeded();
|
||||
}
|
||||
|
||||
public boolean isFullyOpaque() {
|
||||
@@ -108,6 +115,17 @@ public class ScrimView extends View implements Insettable {
|
||||
}
|
||||
}
|
||||
|
||||
private void dispatchVisibilityListenersIfNeeded() {
|
||||
boolean fullyOpaque = isFullyOpaque();
|
||||
if (mLastDispatchedOpaqueness == fullyOpaque) {
|
||||
return;
|
||||
}
|
||||
mLastDispatchedOpaqueness = fullyOpaque;
|
||||
for (int i = 0; i < mOpaquenessListeners.size(); i++) {
|
||||
mOpaquenessListeners.get(i).run();
|
||||
}
|
||||
}
|
||||
|
||||
private SystemUiController getSystemUiController() {
|
||||
if (mSystemUiController == null) {
|
||||
mSystemUiController = BaseActivity.fromContext(getContext()).getSystemUiController();
|
||||
@@ -135,6 +153,22 @@ public class ScrimView extends View implements Insettable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a listener to be notified of whether the scrim is occluding other UI elements.
|
||||
* @see #isFullyOpaque()
|
||||
*/
|
||||
public void addOpaquenessListener(@NonNull Runnable listener) {
|
||||
mOpaquenessListeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes previously registered listener.
|
||||
* @see #addOpaquenessListener(Runnable)
|
||||
*/
|
||||
public void removeOpaquenessListener(@NonNull Runnable listener) {
|
||||
mOpaquenessListeners.remove(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* A Utility interface allowing for other surfaces to draw on ScrimView
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Outline;
|
||||
import android.graphics.Rect;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewOutlineProvider;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import androidx.annotation.UiThread;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.util.Executors;
|
||||
|
||||
/**
|
||||
* Launcher AppWidgetHostView with support for rounded corners and a fallback View.
|
||||
*/
|
||||
public abstract class BaseLauncherAppWidgetHostView extends NavigableAppWidgetHostView {
|
||||
|
||||
protected final LayoutInflater mInflater;
|
||||
|
||||
private final Rect mEnforcedRectangle = new Rect();
|
||||
private final float mEnforcedCornerRadius;
|
||||
private final ViewOutlineProvider mCornerRadiusEnforcementOutline = new ViewOutlineProvider() {
|
||||
@Override
|
||||
public void getOutline(View view, Outline outline) {
|
||||
if (mEnforcedRectangle.isEmpty() || mEnforcedCornerRadius <= 0) {
|
||||
outline.setEmpty();
|
||||
} else {
|
||||
outline.setRoundRect(mEnforcedRectangle, mEnforcedCornerRadius);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public BaseLauncherAppWidgetHostView(Context context) {
|
||||
super(context);
|
||||
|
||||
setExecutor(Executors.THREAD_POOL_EXECUTOR);
|
||||
|
||||
mInflater = LayoutInflater.from(context);
|
||||
mEnforcedCornerRadius = RoundedCornerEnforcement.computeEnforcedRadius(getContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected View getErrorView() {
|
||||
return mInflater.inflate(R.layout.appwidget_error, this, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fall back to error layout instead of showing widget.
|
||||
*/
|
||||
public void switchToErrorView() {
|
||||
// Update the widget with 0 Layout id, to reset the view to error view.
|
||||
updateAppWidget(new RemoteViews(getAppWidgetInfo().provider.getPackageName(), 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
try {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
} catch (final RuntimeException e) {
|
||||
post(this::switchToErrorView);
|
||||
}
|
||||
|
||||
enforceRoundedCorners();
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void resetRoundedCorners() {
|
||||
setOutlineProvider(ViewOutlineProvider.BACKGROUND);
|
||||
setClipToOutline(false);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void enforceRoundedCorners() {
|
||||
if (mEnforcedCornerRadius <= 0 || !RoundedCornerEnforcement.isRoundedCornerEnabled()) {
|
||||
resetRoundedCorners();
|
||||
return;
|
||||
}
|
||||
View background = RoundedCornerEnforcement.findBackground(this);
|
||||
if (background == null
|
||||
|| RoundedCornerEnforcement.hasAppWidgetOptedOut(this, background)) {
|
||||
resetRoundedCorners();
|
||||
return;
|
||||
}
|
||||
RoundedCornerEnforcement.computeRoundedRectangle(this,
|
||||
background,
|
||||
mEnforcedRectangle);
|
||||
setOutlineProvider(mCornerRadiusEnforcementOutline);
|
||||
setClipToOutline(true);
|
||||
}
|
||||
|
||||
/** Returns the corner radius currently enforced, in pixels. */
|
||||
public float getEnforcedCornerRadius() {
|
||||
return mEnforcedCornerRadius;
|
||||
}
|
||||
|
||||
/** Returns true if the corner radius are enforced for this App Widget. */
|
||||
public boolean hasEnforcedCornerRadius() {
|
||||
return getClipToOutline();
|
||||
}
|
||||
}
|
||||
@@ -20,19 +20,16 @@ import android.appwidget.AppWidgetProviderInfo;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Outline;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Handler;
|
||||
import android.os.SystemClock;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.util.SparseIntArray;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewDebug;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewOutlineProvider;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.Advanceable;
|
||||
@@ -40,7 +37,6 @@ import android.widget.RemoteViews;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.UiThread;
|
||||
|
||||
import com.android.launcher3.CheckLongPressHelper;
|
||||
import com.android.launcher3.Launcher;
|
||||
@@ -51,7 +47,6 @@ import com.android.launcher3.dragndrop.DragLayer;
|
||||
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
|
||||
import com.android.launcher3.util.Executors;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.launcher3.views.BaseDragLayer.TouchCompleteListener;
|
||||
import com.android.launcher3.widget.dragndrop.AppWidgetHostViewDragListener;
|
||||
@@ -61,7 +56,7 @@ import java.util.List;
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView
|
||||
public class LauncherAppWidgetHostView extends BaseLauncherAppWidgetHostView
|
||||
implements TouchCompleteListener, View.OnLongClickListener,
|
||||
LocalColorExtractor.Listener {
|
||||
|
||||
@@ -76,8 +71,6 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView
|
||||
// Maximum duration for which updates can be deferred.
|
||||
private static final long UPDATE_LOCK_TIMEOUT_MILLIS = 1000;
|
||||
|
||||
protected final LayoutInflater mInflater;
|
||||
|
||||
private final CheckLongPressHelper mLongPressHelper;
|
||||
protected final Launcher mLauncher;
|
||||
private final Workspace mWorkspace;
|
||||
@@ -101,18 +94,6 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView
|
||||
private final Rect mWidgetSizeAtDrag = new Rect();
|
||||
|
||||
private final RectF mTempRectF = new RectF();
|
||||
private final Rect mEnforcedRectangle = new Rect();
|
||||
private final float mEnforcedCornerRadius;
|
||||
private final ViewOutlineProvider mCornerRadiusEnforcementOutline = new ViewOutlineProvider() {
|
||||
@Override
|
||||
public void getOutline(View view, Outline outline) {
|
||||
if (mEnforcedRectangle.isEmpty() || mEnforcedCornerRadius <= 0) {
|
||||
outline.setEmpty();
|
||||
} else {
|
||||
outline.setRoundRect(mEnforcedRectangle, mEnforcedCornerRadius);
|
||||
}
|
||||
}
|
||||
};
|
||||
private final Object mUpdateLock = new Object();
|
||||
private final ViewGroupFocusHelper mDragLayerRelativeCoordinateHelper;
|
||||
private long mDeferUpdatesUntilMillis = 0;
|
||||
@@ -126,18 +107,15 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView
|
||||
mLauncher = Launcher.getLauncher(context);
|
||||
mWorkspace = mLauncher.getWorkspace();
|
||||
mLongPressHelper = new CheckLongPressHelper(this, this);
|
||||
mInflater = LayoutInflater.from(context);
|
||||
setAccessibilityDelegate(mLauncher.getAccessibilityDelegate());
|
||||
setBackgroundResource(R.drawable.widget_internal_focus_bg);
|
||||
|
||||
setExecutor(Executors.THREAD_POOL_EXECUTOR);
|
||||
if (Utilities.ATLEAST_Q && Themes.getAttrBoolean(mLauncher, R.attr.isWorkspaceDarkText)) {
|
||||
setOnLightBackground(true);
|
||||
}
|
||||
mColorExtractor = LocalColorExtractor.newInstance(getContext());
|
||||
mColorExtractor.setListener(this);
|
||||
|
||||
mEnforcedCornerRadius = RoundedCornerEnforcement.computeEnforcedRadius(getContext());
|
||||
mDragLayerRelativeCoordinateHelper = new ViewGroupFocusHelper(mLauncher.getDragLayer());
|
||||
}
|
||||
|
||||
@@ -168,11 +146,6 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected View getErrorView() {
|
||||
return mInflater.inflate(R.layout.appwidget_error, this, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateAppWidget(RemoteViews remoteViews) {
|
||||
synchronized (mUpdateLock) {
|
||||
@@ -329,28 +302,12 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView
|
||||
}
|
||||
}
|
||||
|
||||
public void switchToErrorView() {
|
||||
// Update the widget with 0 Layout id, to reset the view to error view.
|
||||
updateAppWidget(new RemoteViews(getAppWidgetInfo().provider.getPackageName(), 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
try {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
} catch (final RuntimeException e) {
|
||||
post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
switchToErrorView();
|
||||
}
|
||||
});
|
||||
}
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
|
||||
mIsScrollable = checkScrollableRecursively(this);
|
||||
updateColorExtraction();
|
||||
|
||||
enforceRoundedCorners();
|
||||
}
|
||||
|
||||
/** Starts the drag mode. */
|
||||
@@ -564,40 +521,4 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void resetRoundedCorners() {
|
||||
setOutlineProvider(ViewOutlineProvider.BACKGROUND);
|
||||
setClipToOutline(false);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void enforceRoundedCorners() {
|
||||
if (mEnforcedCornerRadius <= 0 || !RoundedCornerEnforcement.isRoundedCornerEnabled()) {
|
||||
resetRoundedCorners();
|
||||
return;
|
||||
}
|
||||
View background = RoundedCornerEnforcement.findBackground(this);
|
||||
if (background == null
|
||||
|| RoundedCornerEnforcement.hasAppWidgetOptedOut(this, background)) {
|
||||
resetRoundedCorners();
|
||||
return;
|
||||
}
|
||||
RoundedCornerEnforcement.computeRoundedRectangle(this,
|
||||
background,
|
||||
mEnforcedRectangle);
|
||||
setOutlineProvider(mCornerRadiusEnforcementOutline);
|
||||
setClipToOutline(true);
|
||||
}
|
||||
|
||||
/** Returns the corner radius currently enforced, in pixels. */
|
||||
public float getEnforcedCornerRadius() {
|
||||
return mEnforcedCornerRadius;
|
||||
}
|
||||
|
||||
/** Returns true if the corner radius are enforced for this App Widget. */
|
||||
public boolean hasEnforcedCornerRadius() {
|
||||
return getClipToOutline();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ import android.view.View;
|
||||
import android.view.ViewDebug;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.android.launcher3.BaseActivity;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.Reorderable;
|
||||
import com.android.launcher3.dragndrop.DraggableView;
|
||||
@@ -59,7 +58,7 @@ public abstract class NavigableAppWidgetHostView extends AppWidgetHostView
|
||||
@ViewDebug.ExportedProperty(category = "launcher")
|
||||
private boolean mChildrenFocused;
|
||||
|
||||
protected final BaseActivity mActivity;
|
||||
protected final ActivityContext mActivity;
|
||||
|
||||
public NavigableAppWidgetHostView(Context context) {
|
||||
super(context);
|
||||
|
||||
@@ -268,8 +268,8 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView
|
||||
if (availableWidth > 0) {
|
||||
// Recreate the setup text.
|
||||
mSetupTextLayout = new StaticLayout(
|
||||
getResources().getText(R.string.gadget_setup_text), mPaint, availableWidth,
|
||||
Layout.Alignment.ALIGN_CENTER, 1, 0, true);
|
||||
getResources().getText(R.string.gadget_complete_setup_text), mPaint,
|
||||
availableWidth, Layout.Alignment.ALIGN_CENTER, 1, 0, true);
|
||||
int textHeight = mSetupTextLayout.getHeight();
|
||||
|
||||
// Extra icon size due to the setting icon
|
||||
|
||||
Reference in New Issue
Block a user