Snap for 9386067 from 969606e2ba to udc-release
Change-Id: I90a7fe9a852564b6896ad08eed1f7882209a5c94
This commit is contained in:
+7
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,23 +16,19 @@
|
||||
package com.android.launcher3;
|
||||
|
||||
import android.animation.AnimatorSet;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.TargetApi;
|
||||
import android.os.Build;
|
||||
import android.os.CancellationSignal;
|
||||
import android.view.RemoteAnimationTarget;
|
||||
|
||||
import com.android.launcher3.uioverrides.QuickstepLauncher;
|
||||
import com.android.quickstep.util.ActivityLifecycleListener;
|
||||
import com.android.quickstep.util.ActivityInitListener;
|
||||
import com.android.quickstep.util.RemoteAnimationProvider;
|
||||
|
||||
import java.util.function.BiPredicate;
|
||||
|
||||
/**
|
||||
* {@link ActivityLifecycleListener} for the in-launcher recents.
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.P)
|
||||
public class LauncherLifecycleListener extends ActivityLifecycleListener<Launcher> {
|
||||
public class LauncherInitListener extends ActivityInitListener<Launcher> {
|
||||
|
||||
private RemoteAnimationProvider mRemoteAnimationProvider;
|
||||
|
||||
@@ -40,16 +36,13 @@ public class LauncherLifecycleListener extends ActivityLifecycleListener<Launche
|
||||
* @param onInitListener a callback made when the activity is initialized. The callback should
|
||||
* return true to continue receiving callbacks (ie. for if the activity is
|
||||
* recreated).
|
||||
* @param onDestroyListener a callback made when the activity is destroyed.
|
||||
*/
|
||||
public LauncherLifecycleListener(
|
||||
@Nullable BiPredicate<Launcher, Boolean> onInitListener,
|
||||
@Nullable Runnable onDestroyListener) {
|
||||
super(onInitListener, onDestroyListener, Launcher.ACTIVITY_TRACKER);
|
||||
public LauncherInitListener(BiPredicate<Launcher, Boolean> onInitListener) {
|
||||
super(onInitListener, Launcher.ACTIVITY_TRACKER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleActivityReady(Launcher launcher, boolean alreadyOnHome) {
|
||||
public boolean handleInit(Launcher launcher, boolean alreadyOnHome) {
|
||||
if (mRemoteAnimationProvider != null) {
|
||||
QuickstepTransitionManager appTransitionManager =
|
||||
((QuickstepLauncher) launcher).getAppTransitionManager();
|
||||
@@ -75,7 +68,7 @@ public class LauncherLifecycleListener extends ActivityLifecycleListener<Launche
|
||||
}, cancellationSignal);
|
||||
}
|
||||
launcher.deferOverlayCallbacksUntilNextResumeOrStop();
|
||||
return super.handleActivityReady(launcher, alreadyOnHome);
|
||||
return super.handleInit(launcher, alreadyOnHome);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -50,7 +50,6 @@ import static com.android.quickstep.GestureState.STATE_RECENTS_SCROLLING_FINISHE
|
||||
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
|
||||
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.CANCEL_RECENTS_ANIMATION;
|
||||
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.EXPECTING_TASK_APPEARED;
|
||||
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.LAUNCHER_DESTROYED;
|
||||
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.ON_SETTLED_ON_END_TARGET;
|
||||
import static com.android.quickstep.util.VibratorWrapper.OVERVIEW_HAPTIC;
|
||||
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
|
||||
@@ -114,7 +113,7 @@ import com.android.quickstep.GestureState.GestureEndTarget;
|
||||
import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle;
|
||||
import com.android.quickstep.util.ActiveGestureErrorDetector;
|
||||
import com.android.quickstep.util.ActiveGestureLog;
|
||||
import com.android.quickstep.util.ActivityLifecycleListener;
|
||||
import com.android.quickstep.util.ActivityInitListener;
|
||||
import com.android.quickstep.util.AnimatorControllerWithResistance;
|
||||
import com.android.quickstep.util.InputConsumerProxy;
|
||||
import com.android.quickstep.util.InputProxyHandlerFactory;
|
||||
@@ -160,7 +159,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
|
||||
|
||||
protected final BaseActivityInterface<S, T> mActivityInterface;
|
||||
protected final InputConsumerProxy mInputConsumerProxy;
|
||||
protected final ActivityLifecycleListener mActivityInitListener;
|
||||
protected final ActivityInitListener mActivityInitListener;
|
||||
// Callbacks to be made once the recents animation starts
|
||||
private final ArrayList<Runnable> mRecentsAnimationStartCallbacks = new ArrayList<>();
|
||||
private final OnScrollChangedListener mOnRecentsScrollListener = this::onRecentsViewScroll;
|
||||
@@ -329,8 +328,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
|
||||
InputConsumerController inputConsumer) {
|
||||
super(context, deviceState, gestureState);
|
||||
mActivityInterface = gestureState.getActivityInterface();
|
||||
mActivityInitListener = mActivityInterface.createActivityLifecycleListener(
|
||||
this::onActivityInit, this::onActivityDestroy);
|
||||
mActivityInitListener = mActivityInterface.createActivityInitListener(this::onActivityInit);
|
||||
mInputConsumerProxy =
|
||||
new InputConsumerProxy(context, /* rotationSupplier = */ () -> {
|
||||
if (mRecentsView == null) {
|
||||
@@ -521,11 +519,6 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
|
||||
return true;
|
||||
}
|
||||
|
||||
private void onActivityDestroy() {
|
||||
ActiveGestureLog.INSTANCE.addLog("Launcher activity destroyed", LAUNCHER_DESTROYED);
|
||||
onGestureCancelled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the window should be translated horizontally if the recents view scrolls
|
||||
*/
|
||||
|
||||
@@ -60,7 +60,7 @@ import com.android.launcher3.touch.PagedOrientationHandler;
|
||||
import com.android.launcher3.util.DisplayController;
|
||||
import com.android.launcher3.util.NavigationMode;
|
||||
import com.android.launcher3.views.ScrimView;
|
||||
import com.android.quickstep.util.ActivityLifecycleListener;
|
||||
import com.android.quickstep.util.ActivityInitListener;
|
||||
import com.android.quickstep.util.AnimatorControllerWithResistance;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||
@@ -123,17 +123,8 @@ public abstract class BaseActivityInterface<STATE_TYPE extends BaseState<STATE_T
|
||||
public abstract AnimationFactory prepareRecentsUI(RecentsAnimationDeviceState deviceState,
|
||||
boolean activityVisible, Consumer<AnimatorControllerWithResistance> callback);
|
||||
|
||||
/**
|
||||
* Creates a activity listener for activity initialized and/or destroyed. One or both of these
|
||||
* listeners must be provided.
|
||||
*
|
||||
* @param onInitListener a callback made when the activity is initialized. The callback should
|
||||
* return true to continue receiving callbacks (ie. for if the activity is
|
||||
* recreated).
|
||||
* @param onDestroyListener a callback made when the activity is destroyed.
|
||||
*/
|
||||
public abstract ActivityLifecycleListener createActivityLifecycleListener(
|
||||
@Nullable Predicate<Boolean> onInitListener, @Nullable Runnable onDestroyListener);
|
||||
public abstract ActivityInitListener createActivityInitListener(
|
||||
Predicate<Boolean> onInitListener);
|
||||
|
||||
/**
|
||||
* Sets a callback to be run when an activity launch happens while launcher is not yet resumed.
|
||||
|
||||
@@ -36,7 +36,7 @@ import com.android.launcher3.touch.PagedOrientationHandler;
|
||||
import com.android.launcher3.util.DisplayController;
|
||||
import com.android.quickstep.GestureState.GestureEndTarget;
|
||||
import com.android.quickstep.fallback.RecentsState;
|
||||
import com.android.quickstep.util.ActivityLifecycleListener;
|
||||
import com.android.quickstep.util.ActivityInitListener;
|
||||
import com.android.quickstep.util.AnimatorControllerWithResistance;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
|
||||
@@ -88,12 +88,10 @@ public final class FallbackActivityInterface extends
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActivityLifecycleListener createActivityLifecycleListener(
|
||||
@Nullable Predicate<Boolean> onInitListener, @Nullable Runnable onDestroyListener) {
|
||||
return new ActivityLifecycleListener<>(
|
||||
(activity, alreadyOnHome) -> onInitListener.test(alreadyOnHome),
|
||||
onDestroyListener,
|
||||
RecentsActivity.ACTIVITY_TRACKER);
|
||||
public ActivityInitListener createActivityInitListener(
|
||||
Predicate<Boolean> onInitListener) {
|
||||
return new ActivityInitListener<>((activity, alreadyOnHome) ->
|
||||
onInitListener.test(alreadyOnHome), RecentsActivity.ACTIVITY_TRACKER);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -37,7 +37,7 @@ import androidx.annotation.UiThread;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherAnimUtils;
|
||||
import com.android.launcher3.LauncherLifecycleListener;
|
||||
import com.android.launcher3.LauncherInitListener;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.anim.PendingAnimation;
|
||||
import com.android.launcher3.statehandlers.DepthController;
|
||||
@@ -49,7 +49,7 @@ import com.android.launcher3.uioverrides.QuickstepLauncher;
|
||||
import com.android.launcher3.util.DisplayController;
|
||||
import com.android.launcher3.util.NavigationMode;
|
||||
import com.android.quickstep.GestureState.GestureEndTarget;
|
||||
import com.android.quickstep.util.ActivityLifecycleListener;
|
||||
import com.android.quickstep.util.ActivityInitListener;
|
||||
import com.android.quickstep.util.AnimatorControllerWithResistance;
|
||||
import com.android.quickstep.util.LayoutUtils;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
@@ -136,10 +136,9 @@ public final class LauncherActivityInterface extends
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActivityLifecycleListener createActivityLifecycleListener(
|
||||
@Nullable Predicate<Boolean> onInitListener, @Nullable Runnable onDestroyListener) {
|
||||
return new LauncherLifecycleListener((activity, alreadyOnHome) ->
|
||||
onInitListener.test(alreadyOnHome), onDestroyListener);
|
||||
public ActivityInitListener createActivityInitListener(Predicate<Boolean> onInitListener) {
|
||||
return new LauncherInitListener((activity, alreadyOnHome) ->
|
||||
onInitListener.test(alreadyOnHome));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -37,7 +37,7 @@ public class ActiveGestureErrorDetector {
|
||||
ON_SETTLED_ON_END_TARGET, START_RECENTS_ANIMATION, FINISH_RECENTS_ANIMATION,
|
||||
CANCEL_RECENTS_ANIMATION, SET_ON_PAGE_TRANSITION_END_CALLBACK, CANCEL_CURRENT_ANIMATION,
|
||||
CLEANUP_SCREENSHOT, SCROLLER_ANIMATION_ABORTED, TASK_APPEARED, EXPECTING_TASK_APPEARED,
|
||||
FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER, LAUNCHER_DESTROYED,
|
||||
FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER,
|
||||
|
||||
/**
|
||||
* These GestureEvents are specifically associated to state flags that get set in
|
||||
@@ -162,13 +162,6 @@ public class ActiveGestureErrorDetector {
|
||||
+ "before/without setting end target to new task",
|
||||
writer);
|
||||
break;
|
||||
case LAUNCHER_DESTROYED:
|
||||
errorDetected |= printErrorIfTrue(
|
||||
true,
|
||||
prefix,
|
||||
/* errorMessage= */ "Launcher destroyed mid-gesture",
|
||||
writer);
|
||||
break;
|
||||
case STATE_GESTURE_COMPLETED:
|
||||
errorDetected |= printErrorIfTrue(
|
||||
!encounteredEvents.contains(GestureEvent.MOTION_UP),
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.quickstep.util;
|
||||
|
||||
import com.android.launcher3.BaseActivity;
|
||||
import com.android.launcher3.util.ActivityTracker;
|
||||
import com.android.launcher3.util.ActivityTracker.SchedulerCallback;
|
||||
|
||||
import java.util.function.BiPredicate;
|
||||
|
||||
public class ActivityInitListener<T extends BaseActivity> implements
|
||||
SchedulerCallback<T> {
|
||||
|
||||
private BiPredicate<T, Boolean> mOnInitListener;
|
||||
private final ActivityTracker<T> mActivityTracker;
|
||||
|
||||
private boolean mIsRegistered = false;
|
||||
|
||||
/**
|
||||
* @param onInitListener a callback made when the activity is initialized. The callback should
|
||||
* return true to continue receiving callbacks (ie. for if the activity is
|
||||
* recreated).
|
||||
*/
|
||||
public ActivityInitListener(BiPredicate<T, Boolean> onInitListener,
|
||||
ActivityTracker<T> tracker) {
|
||||
mOnInitListener = onInitListener;
|
||||
mActivityTracker = tracker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean init(T activity, boolean alreadyOnHome) {
|
||||
if (!mIsRegistered) {
|
||||
// Don't receive any more updates
|
||||
return false;
|
||||
}
|
||||
return handleInit(activity, alreadyOnHome);
|
||||
}
|
||||
|
||||
protected boolean handleInit(T activity, boolean alreadyOnHome) {
|
||||
return mOnInitListener.test(activity, alreadyOnHome);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the activity-created listener. If the activity is already created, then the
|
||||
* callback provided in the constructor will be called synchronously.
|
||||
*/
|
||||
public void register() {
|
||||
mIsRegistered = true;
|
||||
mActivityTracker.registerCallback(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* After calling this, we won't {@link #init} even when the activity is ready.
|
||||
*/
|
||||
public void unregister() {
|
||||
mActivityTracker.unregisterCallback(this);
|
||||
mIsRegistered = false;
|
||||
mOnInitListener = null;
|
||||
}
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.quickstep.util;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.BaseActivity;
|
||||
import com.android.launcher3.util.ActivityTracker;
|
||||
import com.android.launcher3.util.ActivityTracker.SchedulerCallback;
|
||||
|
||||
import java.util.function.BiPredicate;
|
||||
|
||||
/**
|
||||
* Listener for activity initialized and/or destroyed.
|
||||
*/
|
||||
public class ActivityLifecycleListener<T extends BaseActivity> implements
|
||||
SchedulerCallback<T> {
|
||||
|
||||
private static final String TAG = "ActivityLifecycleListener";
|
||||
|
||||
@Nullable private final BiPredicate<T, Boolean> mOnInitListener;
|
||||
@Nullable private final Runnable mOnDestroyListener;
|
||||
private final ActivityTracker<T> mActivityTracker;
|
||||
|
||||
private boolean mIsRegistered = false;
|
||||
|
||||
/**
|
||||
* One or both of {@code onInitListener} and {@code onInitListener} must be provided, otherwise
|
||||
* the created instance will effectively be a no-op.
|
||||
*
|
||||
* @param onInitListener a callback made when the activity is initialized. The callback should
|
||||
* return true to continue receiving callbacks (ie. for if the activity is
|
||||
* recreated).
|
||||
* @param onDestroyListener a callback made when the activity is destroyed.
|
||||
*/
|
||||
public ActivityLifecycleListener(
|
||||
@Nullable BiPredicate<T, Boolean> onInitListener,
|
||||
@Nullable Runnable onDestroyListener,
|
||||
ActivityTracker<T> tracker) {
|
||||
if (onInitListener == null && onDestroyListener == null) {
|
||||
throw new IllegalArgumentException("Both listeners cannot be null");
|
||||
}
|
||||
mOnInitListener = onInitListener;
|
||||
mOnDestroyListener = onDestroyListener;
|
||||
mActivityTracker = tracker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onActivityReady(T activity, boolean alreadyOnHome) {
|
||||
if (!mIsRegistered) {
|
||||
// Don't receive any more updates
|
||||
return false;
|
||||
}
|
||||
return handleActivityReady(activity, alreadyOnHome);
|
||||
}
|
||||
|
||||
protected boolean handleActivityReady(T activity, boolean alreadyOnHome) {
|
||||
if (mOnInitListener == null) {
|
||||
Log.e(TAG, "Cannot handle init: init listener is null", new Exception());
|
||||
return false;
|
||||
}
|
||||
return mOnInitListener.test(activity, alreadyOnHome);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityDestroyed() {
|
||||
if (mOnDestroyListener == null) {
|
||||
Log.e(TAG, "Cannot clean up: destroy listener is null", new Exception());
|
||||
return;
|
||||
}
|
||||
mOnDestroyListener.run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the activity-created listener. If the activity is already created, then the
|
||||
* callback provided in the constructor will be called synchronously.
|
||||
*/
|
||||
public void register() {
|
||||
mIsRegistered = true;
|
||||
mActivityTracker.registerCallback(this, getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* After calling this, we won't call {@link #onActivityReady} even when the activity is ready.
|
||||
*/
|
||||
public void unregister() {
|
||||
mActivityTracker.unregisterCallback(this, getType());
|
||||
mIsRegistered = false;
|
||||
}
|
||||
|
||||
private int getType() {
|
||||
return mOnInitListener != null && mOnDestroyListener != null
|
||||
? ActivityTracker.TYPE_BOTH
|
||||
: (mOnInitListener != null
|
||||
? ActivityTracker.TYPE_INIT
|
||||
: ActivityTracker.TYPE_DESTROY);
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,6 @@ import android.text.TextUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.util.Patterns;
|
||||
import android.util.Xml;
|
||||
|
||||
@@ -45,7 +44,7 @@ import com.android.launcher3.model.data.LauncherAppWidgetInfo;
|
||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||
import com.android.launcher3.qsb.QsbContainerView;
|
||||
import com.android.launcher3.util.IntArray;
|
||||
import com.android.launcher3.util.PackageManagerHelper;
|
||||
import com.android.launcher3.util.Partner;
|
||||
import com.android.launcher3.util.Thunk;
|
||||
import com.android.launcher3.widget.LauncherWidgetHolder;
|
||||
|
||||
@@ -76,19 +75,16 @@ public class AutoInstallsLayout {
|
||||
|
||||
static AutoInstallsLayout get(Context context, LauncherWidgetHolder appWidgetHolder,
|
||||
LayoutParserCallback callback) {
|
||||
Pair<String, Resources> customizationApkInfo = PackageManagerHelper.findSystemApk(
|
||||
ACTION_LAUNCHER_CUSTOMIZATION, context.getPackageManager());
|
||||
if (customizationApkInfo == null) {
|
||||
Partner partner = Partner.get(context.getPackageManager(), ACTION_LAUNCHER_CUSTOMIZATION);
|
||||
if (partner == null) {
|
||||
return null;
|
||||
}
|
||||
String pkg = customizationApkInfo.first;
|
||||
Resources targetRes = customizationApkInfo.second;
|
||||
InvariantDeviceProfile grid = LauncherAppState.getIDP(context);
|
||||
|
||||
// Try with grid size and hotseat count
|
||||
String layoutName = String.format(Locale.ENGLISH, FORMATTED_LAYOUT_RES_WITH_HOSTEAT,
|
||||
grid.numColumns, grid.numRows, grid.numDatabaseHotseatIcons);
|
||||
int layoutId = targetRes.getIdentifier(layoutName, "xml", pkg);
|
||||
int layoutId = partner.getXmlResId(layoutName);
|
||||
|
||||
// Try with only grid size
|
||||
if (layoutId == 0) {
|
||||
@@ -96,21 +92,21 @@ public class AutoInstallsLayout {
|
||||
+ " not found. Trying layout without hosteat");
|
||||
layoutName = String.format(Locale.ENGLISH, FORMATTED_LAYOUT_RES,
|
||||
grid.numColumns, grid.numRows);
|
||||
layoutId = targetRes.getIdentifier(layoutName, "xml", pkg);
|
||||
layoutId = partner.getXmlResId(layoutName);
|
||||
}
|
||||
|
||||
// Try the default layout
|
||||
if (layoutId == 0) {
|
||||
Log.d(TAG, "Formatted layout: " + layoutName + " not found. Trying the default layout");
|
||||
layoutId = targetRes.getIdentifier(LAYOUT_RES, "xml", pkg);
|
||||
layoutId = partner.getXmlResId(LAYOUT_RES);
|
||||
}
|
||||
|
||||
if (layoutId == 0) {
|
||||
Log.e(TAG, "Layout definition not found in package: " + pkg);
|
||||
Log.e(TAG, "Layout definition not found in package: " + partner.getPackageName());
|
||||
return null;
|
||||
}
|
||||
return new AutoInstallsLayout(context, appWidgetHolder, callback, targetRes, layoutId,
|
||||
TAG_WORKSPACE);
|
||||
return new AutoInstallsLayout(context, appWidgetHolder, callback, partner.getResources(),
|
||||
layoutId, TAG_WORKSPACE);
|
||||
}
|
||||
|
||||
// Object Tags
|
||||
|
||||
@@ -19,6 +19,7 @@ import android.util.Log;
|
||||
import com.android.launcher3.LauncherSettings.Favorites;
|
||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||
import com.android.launcher3.shortcuts.ShortcutKey;
|
||||
import com.android.launcher3.util.Partner;
|
||||
import com.android.launcher3.util.Thunk;
|
||||
import com.android.launcher3.widget.LauncherWidgetHolder;
|
||||
|
||||
@@ -51,6 +52,9 @@ public class DefaultLayoutParser extends AutoInstallsLayout {
|
||||
private static final String ATTR_SHORTCUT_ID = "shortcutId";
|
||||
private static final String ATTR_PACKAGE_NAME = "packageName";
|
||||
|
||||
public static final String RES_PARTNER_FOLDER = "partner_folder";
|
||||
public static final String RES_PARTNER_DEFAULT_LAYOUT = "partner_default_layout";
|
||||
|
||||
// TODO: Remove support for this broadcast, instead use widget options to send bind time options
|
||||
private static final String ACTION_APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE =
|
||||
"com.android.launcher.action.APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE";
|
||||
@@ -278,10 +282,9 @@ public class DefaultLayoutParser extends AutoInstallsLayout {
|
||||
// Folder contents come from an external XML resource
|
||||
final Partner partner = Partner.get(mPackageManager);
|
||||
if (partner != null) {
|
||||
final Resources partnerRes = partner.getResources();
|
||||
final int resId = partnerRes.getIdentifier(Partner.RES_FOLDER,
|
||||
"xml", partner.getPackageName());
|
||||
final int resId = partner.getXmlResId(RES_PARTNER_FOLDER);
|
||||
if (resId != 0) {
|
||||
final Resources partnerRes = partner.getResources();
|
||||
final XmlPullParser partnerParser = partnerRes.getXml(resId);
|
||||
beginDocument(partnerParser, TAG_FOLDER);
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ import com.android.launcher3.util.DisplayController;
|
||||
import com.android.launcher3.util.DisplayController.Info;
|
||||
import com.android.launcher3.util.IntArray;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
import com.android.launcher3.util.Partner;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.launcher3.util.WindowBounds;
|
||||
import com.android.launcher3.util.window.WindowManagerProxy;
|
||||
@@ -112,6 +113,11 @@ public class InvariantDeviceProfile {
|
||||
static final int INDEX_TWO_PANEL_PORTRAIT = 2;
|
||||
static final int INDEX_TWO_PANEL_LANDSCAPE = 3;
|
||||
|
||||
/** These resources are used to override the device profile */
|
||||
private static final String RES_GRID_NUM_ROWS = "grid_num_rows";
|
||||
private static final String RES_GRID_NUM_COLUMNS = "grid_num_columns";
|
||||
private static final String RES_GRID_ICON_SIZE_DP = "grid_icon_size_dp";
|
||||
|
||||
/**
|
||||
* Number of icons per row and column in the workspace.
|
||||
*/
|
||||
@@ -567,8 +573,24 @@ public class InvariantDeviceProfile {
|
||||
*/
|
||||
private void applyPartnerDeviceProfileOverrides(Context context, DisplayMetrics dm) {
|
||||
Partner p = Partner.get(context.getPackageManager());
|
||||
if (p != null) {
|
||||
p.applyInvariantDeviceProfileOverrides(this, dm);
|
||||
if (p == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
int numRows = p.getIntValue(RES_GRID_NUM_ROWS, -1);
|
||||
int numColumns = p.getIntValue(RES_GRID_NUM_COLUMNS, -1);
|
||||
float iconSizePx = p.getDimenValue(RES_GRID_ICON_SIZE_DP, -1);
|
||||
|
||||
if (numRows > 0 && numColumns > 0) {
|
||||
this.numRows = numRows;
|
||||
this.numColumns = numColumns;
|
||||
}
|
||||
if (iconSizePx > 0) {
|
||||
this.iconSize[InvariantDeviceProfile.INDEX_DEFAULT] =
|
||||
Utilities.dpiFromPx(iconSizePx, dm.densityDpi);
|
||||
}
|
||||
} catch (Resources.NotFoundException ex) {
|
||||
Log.e(TAG, "Invalid Partner grid resource!", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.launcher3;
|
||||
|
||||
import static com.android.launcher3.DefaultLayoutParser.RES_PARTNER_DEFAULT_LAYOUT;
|
||||
import static com.android.launcher3.provider.LauncherDbUtils.copyTable;
|
||||
import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
|
||||
import static com.android.launcher3.provider.LauncherDbUtils.tableExists;
|
||||
@@ -34,7 +35,6 @@ import android.content.Intent;
|
||||
import android.content.OperationApplicationException;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ProviderInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.database.DatabaseUtils;
|
||||
import android.database.SQLException;
|
||||
@@ -70,6 +70,7 @@ import com.android.launcher3.util.IntArray;
|
||||
import com.android.launcher3.util.IntSet;
|
||||
import com.android.launcher3.util.NoLocaleSQLiteHelper;
|
||||
import com.android.launcher3.util.PackageManagerHelper;
|
||||
import com.android.launcher3.util.Partner;
|
||||
import com.android.launcher3.util.Thunk;
|
||||
import com.android.launcher3.widget.LauncherWidgetHolder;
|
||||
|
||||
@@ -544,13 +545,11 @@ public class LauncherProvider extends ContentProvider {
|
||||
}
|
||||
if (loader == null) {
|
||||
final Partner partner = Partner.get(getContext().getPackageManager());
|
||||
if (partner != null && partner.hasDefaultLayout()) {
|
||||
final Resources partnerRes = partner.getResources();
|
||||
int workspaceResId = partnerRes.getIdentifier(Partner.RES_DEFAULT_LAYOUT,
|
||||
"xml", partner.getPackageName());
|
||||
if (partner != null) {
|
||||
int workspaceResId = partner.getXmlResId(RES_PARTNER_DEFAULT_LAYOUT);
|
||||
if (workspaceResId != 0) {
|
||||
loader = new DefaultLayoutParser(getContext(), widgetHolder,
|
||||
mOpenHelper, partnerRes, workspaceResId);
|
||||
mOpenHelper, partner.getResources(), workspaceResId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.launcher3;
|
||||
|
||||
import static com.android.launcher3.util.PackageManagerHelper.findSystemApk;
|
||||
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Utilities to discover and interact with partner customizations. There can
|
||||
* only be one set of customizations on a device, and it must be bundled with
|
||||
* the system.
|
||||
*/
|
||||
public class Partner {
|
||||
|
||||
static final String TAG = "Launcher.Partner";
|
||||
|
||||
/** Marker action used to discover partner */
|
||||
private static final String
|
||||
ACTION_PARTNER_CUSTOMIZATION = "com.android.launcher3.action.PARTNER_CUSTOMIZATION";
|
||||
|
||||
public static final String RES_FOLDER = "partner_folder";
|
||||
public static final String RES_WALLPAPERS = "partner_wallpapers";
|
||||
public static final String RES_DEFAULT_LAYOUT = "partner_default_layout";
|
||||
|
||||
public static final String RES_DEFAULT_WALLPAPER_HIDDEN = "default_wallpapper_hidden";
|
||||
public static final String RES_SYSTEM_WALLPAPER_DIR = "system_wallpaper_directory";
|
||||
|
||||
public static final String RES_REQUIRE_FIRST_RUN_FLOW = "requires_first_run_flow";
|
||||
|
||||
/** These resources are used to override the device profile */
|
||||
public static final String RES_GRID_NUM_ROWS = "grid_num_rows";
|
||||
public static final String RES_GRID_NUM_COLUMNS = "grid_num_columns";
|
||||
public static final String RES_GRID_ICON_SIZE_DP = "grid_icon_size_dp";
|
||||
|
||||
/**
|
||||
* Find and return partner details, or {@code null} if none exists.
|
||||
*/
|
||||
public static synchronized Partner get(PackageManager pm) {
|
||||
Pair<String, Resources> apkInfo = findSystemApk(ACTION_PARTNER_CUSTOMIZATION, pm);
|
||||
return apkInfo != null ? new Partner(apkInfo.first, apkInfo.second) : null;
|
||||
}
|
||||
|
||||
private final String mPackageName;
|
||||
private final Resources mResources;
|
||||
|
||||
private Partner(String packageName, Resources res) {
|
||||
mPackageName = packageName;
|
||||
mResources = res;
|
||||
}
|
||||
|
||||
public String getPackageName() {
|
||||
return mPackageName;
|
||||
}
|
||||
|
||||
public Resources getResources() {
|
||||
return mResources;
|
||||
}
|
||||
|
||||
public boolean hasDefaultLayout() {
|
||||
int defaultLayout = getResources().getIdentifier(Partner.RES_DEFAULT_LAYOUT,
|
||||
"xml", getPackageName());
|
||||
return defaultLayout != 0;
|
||||
}
|
||||
|
||||
public boolean hasFolder() {
|
||||
int folder = getResources().getIdentifier(Partner.RES_FOLDER,
|
||||
"xml", getPackageName());
|
||||
return folder != 0;
|
||||
}
|
||||
|
||||
public boolean hideDefaultWallpaper() {
|
||||
int resId = getResources().getIdentifier(RES_DEFAULT_WALLPAPER_HIDDEN, "bool",
|
||||
getPackageName());
|
||||
return resId != 0 && getResources().getBoolean(resId);
|
||||
}
|
||||
|
||||
public File getWallpaperDirectory() {
|
||||
int resId = getResources().getIdentifier(RES_SYSTEM_WALLPAPER_DIR, "string",
|
||||
getPackageName());
|
||||
return (resId != 0) ? new File(getResources().getString(resId)) : null;
|
||||
}
|
||||
|
||||
public boolean requiresFirstRunFlow() {
|
||||
int resId = getResources().getIdentifier(RES_REQUIRE_FIRST_RUN_FLOW, "bool",
|
||||
getPackageName());
|
||||
return resId != 0 && getResources().getBoolean(resId);
|
||||
}
|
||||
|
||||
public void applyInvariantDeviceProfileOverrides(InvariantDeviceProfile inv, DisplayMetrics dm) {
|
||||
int numRows = -1;
|
||||
int numColumns = -1;
|
||||
float iconSize = -1;
|
||||
|
||||
try {
|
||||
int resId = getResources().getIdentifier(RES_GRID_NUM_ROWS,
|
||||
"integer", getPackageName());
|
||||
if (resId > 0) {
|
||||
numRows = getResources().getInteger(resId);
|
||||
}
|
||||
|
||||
resId = getResources().getIdentifier(RES_GRID_NUM_COLUMNS,
|
||||
"integer", getPackageName());
|
||||
if (resId > 0) {
|
||||
numColumns = getResources().getInteger(resId);
|
||||
}
|
||||
|
||||
resId = getResources().getIdentifier(RES_GRID_ICON_SIZE_DP,
|
||||
"dimen", getPackageName());
|
||||
if (resId > 0) {
|
||||
int px = getResources().getDimensionPixelSize(resId);
|
||||
iconSize = Utilities.dpiFromPx((float) px, dm.densityDpi);
|
||||
}
|
||||
} catch (Resources.NotFoundException ex) {
|
||||
Log.e(TAG, "Invalid Partner grid resource!", ex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (numRows > 0 && numColumns > 0) {
|
||||
inv.numRows = numRows;
|
||||
inv.numColumns = numColumns;
|
||||
}
|
||||
|
||||
if (iconSize > 0) {
|
||||
inv.iconSize[InvariantDeviceProfile.INDEX_DEFAULT] = iconSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,14 +89,6 @@ public final class FeatureFlags {
|
||||
getDebugFlag("ENABLE_FLOATING_SEARCH_BAR", false,
|
||||
"Keep All Apps search bar at the bottom (but above keyboard if open)");
|
||||
|
||||
public static final BooleanFlag ENABLE_QUICK_LAUNCH_V2 = new DeviceFlag(
|
||||
"ENABLE_QUICK_LAUNCH_V2", false, "Use quick launch v2 "
|
||||
+ "behavior. Quick search and quick launch v1 would be unavailable if this is enabled");
|
||||
|
||||
public static final BooleanFlag GBOARD_UPDATE_ENTER_KEY = new DeviceFlag(
|
||||
"GBOARD_UPDATE_ENTER_KEY", false, "Update gBoard enter key "
|
||||
+ "icon dynamically based on top search content for Quick Launch V2");
|
||||
|
||||
public static final BooleanFlag ENABLE_HIDE_HEADER = new DeviceFlag("ENABLE_HIDE_HEADER",
|
||||
true, "Hide header on keyboard before typing in all apps");
|
||||
|
||||
@@ -374,6 +366,11 @@ public final class FeatureFlags {
|
||||
"Enable the ability to tap a staged app during split select to launch it in full screen"
|
||||
);
|
||||
|
||||
public static final BooleanFlag ENABLE_FORCED_MONO_ICON = getDebugFlag(
|
||||
"ENABLE_FORCED_MONO_ICON", false,
|
||||
"Enable the ability to generate monochromatic icons, if it is not provided by the app"
|
||||
);
|
||||
|
||||
public static void initialize(Context context) {
|
||||
synchronized (sDebugFlags) {
|
||||
for (DebugFlag flag : sDebugFlags) {
|
||||
|
||||
@@ -74,7 +74,7 @@ public abstract class BaseItemDragListener implements View.OnDragListener, DragS
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onActivityReady(Launcher launcher, boolean alreadyOnHome) {
|
||||
public boolean init(Launcher launcher, boolean alreadyOnHome) {
|
||||
AbstractFloatingView.closeAllOpenViews(launcher, alreadyOnHome);
|
||||
launcher.getStateManager().goToState(NORMAL, alreadyOnHome /* animated */);
|
||||
launcher.getDragLayer().setOnDragListener(this);
|
||||
|
||||
@@ -72,8 +72,8 @@ public class PinItemDragListener extends BaseItemDragListener {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onActivityReady(Launcher launcher, boolean alreadyOnHome) {
|
||||
super.onActivityReady(launcher, alreadyOnHome);
|
||||
public boolean init(Launcher launcher, boolean alreadyOnHome) {
|
||||
super.init(launcher, alreadyOnHome);
|
||||
if (!alreadyOnHome) {
|
||||
launcher.useFadeOutAnimationForLauncherStart(mCancelSignal);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,10 @@
|
||||
|
||||
package com.android.launcher3.icons;
|
||||
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_FORCED_MONO_ICON;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.graphics.IconShape;
|
||||
@@ -68,6 +71,8 @@ public class LauncherIcons extends BaseIconFactory implements AutoCloseable {
|
||||
|
||||
private LauncherIcons next;
|
||||
|
||||
private MonochromeIconFactory mMonochromeIconFactory;
|
||||
|
||||
protected LauncherIcons(Context context, int fillResIconDpi, int iconBitmapSize, int poolId) {
|
||||
super(context, fillResIconDpi, iconBitmapSize, IconShape.getShape().enableShapeDetection());
|
||||
mMonoIconEnabled = Themes.isThemedIconEnabled(context);
|
||||
@@ -90,6 +95,18 @@ public class LauncherIcons extends BaseIconFactory implements AutoCloseable {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Drawable getMonochromeDrawable(Drawable base) {
|
||||
Drawable mono = super.getMonochromeDrawable(base);
|
||||
if (mono != null || !ENABLE_FORCED_MONO_ICON.get()) {
|
||||
return mono;
|
||||
}
|
||||
if (mMonochromeIconFactory == null) {
|
||||
mMonochromeIconFactory = new MonochromeIconFactory(mIconBitmapSize);
|
||||
}
|
||||
return mMonochromeIconFactory.wrap(base);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
recycle();
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.icons;
|
||||
|
||||
import static android.graphics.Paint.FILTER_BITMAP_FLAG;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Bitmap.Config;
|
||||
import android.graphics.BlendMode;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.ColorMatrix;
|
||||
import android.graphics.ColorMatrixColorFilter;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.AdaptiveIconDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import com.android.launcher3.icons.BaseIconFactory.ClippedMonoDrawable;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Utility class to generate monochrome icons version for a given drawable.
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.TIRAMISU)
|
||||
public class MonochromeIconFactory extends Drawable {
|
||||
|
||||
private final Bitmap mFlatBitmap;
|
||||
private final Canvas mFlatCanvas;
|
||||
private final Paint mCopyPaint;
|
||||
|
||||
private final Bitmap mAlphaBitmap;
|
||||
private final Canvas mAlphaCanvas;
|
||||
private final byte[] mPixels;
|
||||
|
||||
private final int mBitmapSize;
|
||||
private final int mEdgePixelLength;
|
||||
|
||||
private final Paint mDrawPaint;
|
||||
private final Rect mSrcRect;
|
||||
|
||||
MonochromeIconFactory(int iconBitmapSize) {
|
||||
float extraFactor = AdaptiveIconDrawable.getExtraInsetFraction();
|
||||
float viewPortScale = 1 / (1 + 2 * extraFactor);
|
||||
mBitmapSize = Math.round(iconBitmapSize * 2 * viewPortScale);
|
||||
mPixels = new byte[mBitmapSize * mBitmapSize];
|
||||
mEdgePixelLength = mBitmapSize * (mBitmapSize - iconBitmapSize) / 2;
|
||||
|
||||
mFlatBitmap = Bitmap.createBitmap(mBitmapSize, mBitmapSize, Config.ARGB_8888);
|
||||
mFlatCanvas = new Canvas(mFlatBitmap);
|
||||
|
||||
mAlphaBitmap = Bitmap.createBitmap(mBitmapSize, mBitmapSize, Config.ALPHA_8);
|
||||
mAlphaCanvas = new Canvas(mAlphaBitmap);
|
||||
|
||||
mDrawPaint = new Paint(FILTER_BITMAP_FLAG);
|
||||
mDrawPaint.setColor(Color.WHITE);
|
||||
mSrcRect = new Rect(0, 0, mBitmapSize, mBitmapSize);
|
||||
|
||||
mCopyPaint = new Paint(FILTER_BITMAP_FLAG);
|
||||
mCopyPaint.setBlendMode(BlendMode.SRC);
|
||||
|
||||
// Crate a color matrix which converts the icon to grayscale and then uses the average
|
||||
// of RGB components as the alpha component.
|
||||
ColorMatrix satMatrix = new ColorMatrix();
|
||||
satMatrix.setSaturation(0);
|
||||
float[] vals = satMatrix.getArray();
|
||||
vals[15] = vals[16] = vals[17] = .3333f;
|
||||
vals[18] = vals[19] = 0;
|
||||
mCopyPaint.setColorFilter(new ColorMatrixColorFilter(vals));
|
||||
}
|
||||
|
||||
private void drawDrawable(Drawable drawable) {
|
||||
if (drawable != null) {
|
||||
drawable.setBounds(0, 0, mBitmapSize, mBitmapSize);
|
||||
drawable.draw(mFlatCanvas);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a monochrome version of the provided drawable
|
||||
*/
|
||||
@WorkerThread
|
||||
public Drawable wrap(Drawable icon) {
|
||||
if (icon instanceof AdaptiveIconDrawable) {
|
||||
AdaptiveIconDrawable aid = (AdaptiveIconDrawable) icon;
|
||||
mFlatCanvas.drawColor(Color.BLACK);
|
||||
drawDrawable(aid.getBackground());
|
||||
drawDrawable(aid.getForeground());
|
||||
generateMono();
|
||||
return new ClippedMonoDrawable(this);
|
||||
} else {
|
||||
mFlatCanvas.drawColor(Color.WHITE);
|
||||
drawDrawable(icon);
|
||||
generateMono();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private void generateMono() {
|
||||
mAlphaCanvas.drawBitmap(mFlatBitmap, 0, 0, mCopyPaint);
|
||||
|
||||
// Scale the end points:
|
||||
ByteBuffer buffer = ByteBuffer.wrap(mPixels);
|
||||
buffer.rewind();
|
||||
mAlphaBitmap.copyPixelsToBuffer(buffer);
|
||||
|
||||
int min = 0xFF;
|
||||
int max = 0;
|
||||
for (byte b : mPixels) {
|
||||
min = Math.min(min, b & 0xFF);
|
||||
max = Math.max(max, b & 0xFF);
|
||||
}
|
||||
|
||||
if (min < max) {
|
||||
// rescale pixels to increase contrast
|
||||
float range = max - min;
|
||||
|
||||
// In order to check if the colors should be flipped, we just take the average color
|
||||
// of top and bottom edge which should correspond to be background color. If the edge
|
||||
// colors have more opacity, we flip the colors;
|
||||
int sum = 0;
|
||||
for (int i = 0; i < mEdgePixelLength; i++) {
|
||||
sum += (mPixels[i] & 0xFF);
|
||||
sum += (mPixels[mPixels.length - 1 - i] & 0xFF);
|
||||
}
|
||||
float edgeAverage = sum / (mEdgePixelLength * 2f);
|
||||
float edgeMapped = (edgeAverage - min) / range;
|
||||
boolean flipColor = edgeMapped > .5f;
|
||||
|
||||
for (int i = 0; i < mPixels.length; i++) {
|
||||
int p = mPixels[i] & 0xFF;
|
||||
int p2 = Math.round((p - min) * 0xFF / range);
|
||||
mPixels[i] = flipColor ? (byte) (255 - p2) : (byte) (p2);
|
||||
}
|
||||
buffer.rewind();
|
||||
mAlphaBitmap.copyPixelsFromBuffer(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas) {
|
||||
canvas.drawBitmap(mAlphaBitmap, mSrcRect, getBounds(), mDrawPaint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpacity() {
|
||||
return PixelFormat.TRANSLUCENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(int i) {
|
||||
mDrawPaint.setAlpha(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColorFilter(ColorFilter colorFilter) {
|
||||
mDrawPaint.setColorFilter(colorFilter);
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,8 @@ import androidx.annotation.Nullable;
|
||||
import com.android.launcher3.BaseActivity;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
/**
|
||||
@@ -28,15 +30,8 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
||||
*/
|
||||
public final class ActivityTracker<T extends BaseActivity> {
|
||||
|
||||
public static final int TYPE_INIT = 0;
|
||||
public static final int TYPE_DESTROY = 1;
|
||||
public static final int TYPE_BOTH = 2;
|
||||
|
||||
private WeakReference<T> mCurrentActivity = new WeakReference<>(null);
|
||||
private CopyOnWriteArrayList<SchedulerCallback<T>> mActivityReadyCallbacks =
|
||||
new CopyOnWriteArrayList<>();
|
||||
private CopyOnWriteArrayList<SchedulerCallback<T>> mActivityDestroyedCallbacks =
|
||||
new CopyOnWriteArrayList<>();
|
||||
private CopyOnWriteArrayList<SchedulerCallback<T>> mCallbacks = new CopyOnWriteArrayList<>();
|
||||
|
||||
@Nullable
|
||||
public <R extends T> R getCreatedActivity() {
|
||||
@@ -47,74 +42,32 @@ public final class ActivityTracker<T extends BaseActivity> {
|
||||
if (mCurrentActivity.get() == activity) {
|
||||
mCurrentActivity.clear();
|
||||
}
|
||||
for (SchedulerCallback<T> cb : mActivityDestroyedCallbacks) {
|
||||
cb.onActivityDestroyed();
|
||||
unregisterCallback(cb, TYPE_DESTROY);
|
||||
}
|
||||
}
|
||||
|
||||
/** Registers an activity create callback. */
|
||||
/**
|
||||
* Call {@link SchedulerCallback#init(BaseActivity, boolean)} when the
|
||||
* activity is ready. If the activity is already created, this is called immediately.
|
||||
*
|
||||
* The tracker maintains a strong ref to the callback, so it is up to the caller to return
|
||||
* {@code false} in the callback OR to unregister the callback explicitly.
|
||||
*
|
||||
* @param callback The callback to call init() on when the activity is ready.
|
||||
*/
|
||||
public void registerCallback(SchedulerCallback<T> callback) {
|
||||
registerCallback(callback, TYPE_INIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call {@link SchedulerCallback#onActivityReady(BaseActivity, boolean)} when the
|
||||
* activity is ready and/or {@link SchedulerCallback#onActivityDestroyed()} when the activity
|
||||
* is destroyed.
|
||||
*
|
||||
* If type is {@link ActivityTracker#TYPE_INIT} TYPE_INIT or
|
||||
* {@link ActivityTracker#TYPE_BOTH} and the activity is already created, this
|
||||
* {@link SchedulerCallback#onActivityReady(BaseActivity, boolean)} is called immediately.
|
||||
*
|
||||
* If type is {@link ActivityTracker#TYPE_DESTROY} or
|
||||
* {@link ActivityTracker#TYPE_BOTH} and the activity is already destroyed,
|
||||
* {@link SchedulerCallback#onActivityDestroyed()} is called immediately.
|
||||
*
|
||||
* The tracker maintains a strong ref to the callbacks, so it is up to the caller to return
|
||||
* {@code false} in {@link SchedulerCallback#onActivityReady(BaseActivity, boolean)} OR to
|
||||
* unregister the callback explicitly.
|
||||
*
|
||||
* @param callback The callback to call init() or cleanUp() on when the activity is ready or
|
||||
* destroyed.
|
||||
* @param type whether to use this callback on activity create, destroy or both.
|
||||
*/
|
||||
public void registerCallback(SchedulerCallback<T> callback, int type) {
|
||||
T activity = mCurrentActivity.get();
|
||||
if (type == TYPE_INIT || type == TYPE_BOTH) {
|
||||
mActivityReadyCallbacks.add(callback);
|
||||
if (activity != null) {
|
||||
if (!callback.onActivityReady(activity, activity.isStarted())) {
|
||||
unregisterCallback(callback, TYPE_INIT);
|
||||
}
|
||||
mCallbacks.add(callback);
|
||||
if (activity != null) {
|
||||
if (!callback.init(activity, activity.isStarted())) {
|
||||
unregisterCallback(callback);
|
||||
}
|
||||
}
|
||||
if (type == TYPE_DESTROY || type == TYPE_BOTH) {
|
||||
mActivityDestroyedCallbacks.add(callback);
|
||||
if (activity == null) {
|
||||
callback.onActivityDestroyed();
|
||||
unregisterCallback(callback, TYPE_DESTROY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters a registered activity create callback.
|
||||
*/
|
||||
public void unregisterCallback(SchedulerCallback<T> callback) {
|
||||
unregisterCallback(callback, TYPE_INIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters a registered callback.
|
||||
*/
|
||||
public void unregisterCallback(SchedulerCallback<T> callback, int type) {
|
||||
if (type == TYPE_INIT || type == TYPE_BOTH) {
|
||||
mActivityReadyCallbacks.remove(callback);
|
||||
}
|
||||
if (type == TYPE_DESTROY || type == TYPE_BOTH) {
|
||||
mActivityDestroyedCallbacks.remove(callback);
|
||||
}
|
||||
public void unregisterCallback(SchedulerCallback<T> callback) {
|
||||
mCallbacks.remove(callback);
|
||||
}
|
||||
|
||||
public boolean handleCreate(T activity) {
|
||||
@@ -128,8 +81,8 @@ public final class ActivityTracker<T extends BaseActivity> {
|
||||
|
||||
private boolean handleIntent(T activity, boolean alreadyOnHome) {
|
||||
boolean handled = false;
|
||||
for (SchedulerCallback<T> cb : mActivityReadyCallbacks) {
|
||||
if (!cb.onActivityReady(activity, alreadyOnHome)) {
|
||||
for (SchedulerCallback<T> cb : mCallbacks) {
|
||||
if (!cb.init(activity, alreadyOnHome)) {
|
||||
// Callback doesn't want any more updates
|
||||
unregisterCallback(cb);
|
||||
}
|
||||
@@ -145,11 +98,6 @@ public final class ActivityTracker<T extends BaseActivity> {
|
||||
* @param alreadyOnHome Whether the activity is already started.
|
||||
* @return Whether to continue receiving callbacks (i.e. if the activity is recreated).
|
||||
*/
|
||||
boolean onActivityReady(T activity, boolean alreadyOnHome);
|
||||
|
||||
/**
|
||||
* Called then the activity gets destroyed.
|
||||
*/
|
||||
default void onActivityDestroyed() { }
|
||||
boolean init(T activity, boolean alreadyOnHome);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +131,10 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable {
|
||||
* Returns whether taskbar is transient.
|
||||
*/
|
||||
public static boolean isTransientTaskbar(Context context) {
|
||||
if (FORCE_PERSISTENT_TASKBAR.get()) {
|
||||
// TODO(b/258604917): When running in test harness, use !sTransientTaskbarStatusForTests
|
||||
// once tests are updated to expect new persistent behavior such as not allowing long press
|
||||
// to stash.
|
||||
if (!Utilities.IS_RUNNING_IN_TEST_HARNESS && FORCE_PERSISTENT_TASKBAR.get()) {
|
||||
return false;
|
||||
}
|
||||
return getNavigationMode(context) == NavigationMode.NO_BUTTON
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package com.android.launcher3.util;
|
||||
|
||||
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
|
||||
|
||||
import android.app.AppOpsManager;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.ComponentName;
|
||||
@@ -31,7 +29,6 @@ import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Rect;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
@@ -40,7 +37,6 @@ import android.os.PatternMatcher;
|
||||
import android.os.UserHandle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -295,25 +291,6 @@ public class PackageManagerHelper {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a system apk which had a broadcast receiver listening to a particular action.
|
||||
* @param action intent action used to find the apk
|
||||
* @return a pair of apk package name and the resources.
|
||||
*/
|
||||
public static Pair<String, Resources> findSystemApk(String action, PackageManager pm) {
|
||||
final Intent intent = new Intent(action);
|
||||
for (ResolveInfo info : pm.queryBroadcastReceivers(intent, MATCH_SYSTEM_ONLY)) {
|
||||
final String packageName = info.activityInfo.packageName;
|
||||
try {
|
||||
final Resources res = pm.getResourcesForApplication(packageName);
|
||||
return Pair.create(packageName, res);
|
||||
} catch (NameNotFoundException e) {
|
||||
Log.w(TAG, "Failed to find resources for " + packageName);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the intent is a valid launch intent for a launcher activity of an app.
|
||||
* This is used to identify shortcuts which are different from the ones exposed by the
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.util;
|
||||
|
||||
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
/**
|
||||
* Utilities to discover and interact with partner customizations. There can
|
||||
* only be one set of customizations on a device, and it must be bundled with
|
||||
* the system.
|
||||
*/
|
||||
public class Partner {
|
||||
|
||||
static final String TAG = "Launcher.Partner";
|
||||
|
||||
/** Marker action used to discover partner */
|
||||
private static final String
|
||||
ACTION_PARTNER_CUSTOMIZATION = "com.android.launcher3.action.PARTNER_CUSTOMIZATION";
|
||||
|
||||
/**
|
||||
* Find and return partner details, or {@code null} if none exists.
|
||||
*/
|
||||
public static Partner get(PackageManager pm) {
|
||||
return get(pm, ACTION_PARTNER_CUSTOMIZATION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find and return partner details, or {@code null} if none exists.
|
||||
*/
|
||||
public static Partner get(PackageManager pm, String action) {
|
||||
Pair<String, Resources> apkInfo = findSystemApk(action, pm);
|
||||
return apkInfo != null ? new Partner(apkInfo.first, apkInfo.second) : null;
|
||||
}
|
||||
|
||||
private final String mPackageName;
|
||||
private final Resources mResources;
|
||||
|
||||
private Partner(String packageName, Resources res) {
|
||||
mPackageName = packageName;
|
||||
mResources = res;
|
||||
}
|
||||
|
||||
public String getPackageName() {
|
||||
return mPackageName;
|
||||
}
|
||||
|
||||
public Resources getResources() {
|
||||
return mResources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the xml resource Id for the provided name, or 0 is the resource is not found
|
||||
*/
|
||||
public int getXmlResId(String layoutName) {
|
||||
return getResources().getIdentifier(layoutName, "xml", getPackageName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the integer resource value for the provided resource name,
|
||||
* or default value if the resource name is not present
|
||||
*/
|
||||
public int getIntValue(String resName, int defaultValue) {
|
||||
int resId = getResources().getIdentifier(resName, "integer", getPackageName());
|
||||
return resId > 0 ? getResources().getInteger(resId) : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the dimension value for the provided resource name,
|
||||
* or default value if the resource name is not present
|
||||
*/
|
||||
public float getDimenValue(String resName, int defaultValue) {
|
||||
int resId = getResources().getIdentifier(resName, "dimen", getPackageName());
|
||||
return resId > 0 ? getResources().getDimension(resId) : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a system apk which had a broadcast receiver listening to a particular action.
|
||||
* @param action intent action used to find the apk
|
||||
* @return a pair of apk package name and the resources.
|
||||
*/
|
||||
private static Pair<String, Resources> findSystemApk(String action, PackageManager pm) {
|
||||
final Intent intent = new Intent(action);
|
||||
for (ResolveInfo info : pm.queryBroadcastReceivers(intent, MATCH_SYSTEM_ONLY)) {
|
||||
final String packageName = info.activityInfo.packageName;
|
||||
try {
|
||||
final Resources res = pm.getResourcesForApplication(packageName);
|
||||
return Pair.create(packageName, res);
|
||||
} catch (NameNotFoundException e) {
|
||||
Log.w(TAG, "Failed to find resources for " + packageName);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -55,7 +55,7 @@ public class SearchResultFromQsb {
|
||||
}
|
||||
|
||||
/** Find the web suggestion from search suggestion's title text */
|
||||
public void findWebSuggest(String text) {
|
||||
public void verifyWebSuggestIsPresent(String text) {
|
||||
ArrayList<UiObject2> goldenGateResults =
|
||||
new ArrayList<>(mLauncher.waitForObjectsInContainer(
|
||||
mLauncher.waitForSystemLauncherObject(SEARCH_CONTAINER_RES_ID),
|
||||
|
||||
Reference in New Issue
Block a user