Merge "Add EDU lottie animations for persistent and transient." into tm-qpr-dev
diff --git a/quickstep/src/com/android/launcher3/LauncherLifecycleListener.java b/quickstep/src/com/android/launcher3/LauncherInitListener.java
similarity index 78%
rename from quickstep/src/com/android/launcher3/LauncherLifecycleListener.java
rename to quickstep/src/com/android/launcher3/LauncherInitListener.java
index 82c646d..28bd701 100644
--- a/quickstep/src/com/android/launcher3/LauncherLifecycleListener.java
+++ b/quickstep/src/com/android/launcher3/LauncherInitListener.java
@@ -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 @@
* @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 @@
}, cancellationSignal);
}
launcher.deferOverlayCallbacksUntilNextResumeOrStop();
- return super.handleActivityReady(launcher, alreadyOnHome);
+ return super.handleInit(launcher, alreadyOnHome);
}
@Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index bc69088..049c672 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -32,6 +32,7 @@
import android.os.Handler;
import android.os.SystemProperties;
import android.provider.Settings;
+import android.util.Log;
import android.view.Display;
import androidx.annotation.NonNull;
@@ -224,8 +225,13 @@
return;
}
mActivity = activity;
- mUnfoldProgressProvider.setSourceProvider(getUnfoldTransitionProgressProviderForActivity(
- activity));
+ UnfoldTransitionProgressProvider unfoldTransitionProgressProvider =
+ getUnfoldTransitionProgressProviderForActivity(activity);
+ if (unfoldTransitionProgressProvider == null) {
+ Log.e("b/261320823", "UnfoldTransitionProgressProvider null in setActivity. "
+ + "Unfold animation for launcher will not work.");
+ }
+ mUnfoldProgressProvider.setSourceProvider(unfoldTransitionProgressProvider);
if (mTaskbarActivityContext != null) {
mTaskbarActivityContext.setUIController(
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 36d9686..13d0be5 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -63,6 +63,7 @@
import android.os.CancellationSignal;
import android.os.IBinder;
import android.os.SystemProperties;
+import android.util.Log;
import android.view.Display;
import android.view.HapticFeedbackConstants;
import android.view.RemoteAnimationTarget;
@@ -720,6 +721,7 @@
mUnfoldTransitionProgressProvider,
mRotationChangeProvider
);
+ Log.d("b/261320823", "initUnfoldTransitionProgressProvider completed");
}
}
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index e41841a..3d8ffc4 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -50,7 +50,6 @@
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.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 @@
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;
@@ -330,8 +329,7 @@
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) {
@@ -522,11 +520,6 @@
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
*/
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 5523518..274b686 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -60,7 +60,7 @@
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 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.
diff --git a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
index a658566..ae9fb0b 100644
--- a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
@@ -36,7 +36,7 @@
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 @@
}
@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
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index cb54d2e..9ff9416 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -37,7 +37,7 @@
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.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 @@
}
@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
diff --git a/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java b/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java
index 0fdd8b5..60065fb 100644
--- a/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java
+++ b/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java
@@ -37,7 +37,7 @@
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 @@
+ "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),
diff --git a/quickstep/src/com/android/quickstep/util/ActivityInitListener.java b/quickstep/src/com/android/quickstep/util/ActivityInitListener.java
new file mode 100644
index 0000000..aeec36f
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/ActivityInitListener.java
@@ -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;
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/util/ActivityLifecycleListener.java b/quickstep/src/com/android/quickstep/util/ActivityLifecycleListener.java
deleted file mode 100644
index 1edf188..0000000
--- a/quickstep/src/com/android/quickstep/util/ActivityLifecycleListener.java
+++ /dev/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);
- }
-}
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index f7600ff..47bef7b 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -63,6 +63,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.RuleChain;
@@ -167,6 +168,7 @@
// b/143488140
//@NavigationModeSwitch
+ @Ignore
@Test
public void goToOverviewFromHome() {
mDevice.pressHome();
@@ -178,6 +180,7 @@
// b/143488140
//@NavigationModeSwitch
+ @Ignore
@Test
public void goToOverviewFromApp() {
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
@@ -213,6 +216,7 @@
// b/143488140
//@NavigationModeSwitch
+ @Ignore
@Test
public void testOverview() {
startAppFast(getAppPackageName());
diff --git a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
index 401b967..df5303f 100644
--- a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
+++ b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
@@ -24,6 +24,7 @@
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -56,6 +57,7 @@
eventProcessor.finishIteration();
}
+ @Ignore
@Test
@NavigationModeSwitch
public void testStressPressHome() {
@@ -68,6 +70,7 @@
}
}
+ @Ignore
@Test
@NavigationModeSwitch
public void testStressSwipeToOverview() {
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index cc561c6..9a2fcc0 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -44,6 +44,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -224,6 +225,7 @@
return launcher.<RecentsView>getOverviewPanel().getBottomRowTaskCountForTablet();
}
+ @Ignore
@Test
@NavigationModeSwitch
@PortraitLandscape
@@ -236,6 +238,7 @@
isInState(() -> LauncherState.OVERVIEW));
}
+ @Ignore
@Test
@NavigationModeSwitch
@PortraitLandscape
@@ -363,6 +366,7 @@
waitForState("Launcher internal state didn't switch to Home", () -> LauncherState.NORMAL);
}
+ @Ignore
@Test
@PortraitLandscape
public void testOverviewForTablet() throws Exception {
diff --git a/res/layout/all_apps_content.xml b/res/layout/all_apps_content.xml
index b33029f..773ab8d 100644
--- a/res/layout/all_apps_content.xml
+++ b/res/layout/all_apps_content.xml
@@ -44,6 +44,13 @@
</com.android.launcher3.allapps.FloatingHeaderView>
+ <View
+ android:id="@+id/search_protection"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="gone"
+ android:forceHasOverlappingRendering="false" />
+
<include layout="@layout/search_container_all_apps" />
<include layout="@layout/all_apps_fast_scroller" />
diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java
index efdd5e1..55ede6c 100644
--- a/src/com/android/launcher3/AutoInstallsLayout.java
+++ b/src/com/android/launcher3/AutoInstallsLayout.java
@@ -31,7 +31,6 @@
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.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 @@
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 @@
+ " 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
diff --git a/src/com/android/launcher3/CheckLongPressHelper.java b/src/com/android/launcher3/CheckLongPressHelper.java
index c707df0..ec29b29 100644
--- a/src/com/android/launcher3/CheckLongPressHelper.java
+++ b/src/com/android/launcher3/CheckLongPressHelper.java
@@ -16,12 +16,15 @@
package com.android.launcher3;
+import android.os.Handler;
+import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
/**
- * Utility class to handle tripper long press on a view with custom timeout and stylus event
+ * Utility class to handle tripper long press or right click on a view with custom timeout and
+ * stylus event
*/
public class CheckLongPressHelper {
@@ -34,6 +37,7 @@
private float mLongPressTimeoutFactor = DEFAULT_LONG_PRESS_TIMEOUT_FACTOR;
private boolean mHasPerformedLongPress;
+ private boolean mIsInMouseRightClick;
private Runnable mPendingCheckForLongPress;
@@ -59,6 +63,26 @@
// start fresh on touch down.
cancelLongPress();
+ // Mouse right click should immediately trigger a long press
+ if (isMouseRightClickDownOrMove(ev)) {
+ mIsInMouseRightClick = true;
+ triggerLongPress();
+ final Handler handler = mView.getHandler();
+ if (handler != null) {
+ // Send an ACTION_UP to end this click gesture to avoid user dragging with
+ // mouse's right button. Note that we need to call
+ // {@link Handler#postAtFrontOfQueue()} instead of {@link View#post()} to
+ // make sure ACTION_UP is sent before any ACTION_MOVE if user is dragging.
+ final MotionEvent actionUpEvent = MotionEvent.obtain(ev);
+ actionUpEvent.setAction(MotionEvent.ACTION_UP);
+ handler.postAtFrontOfQueue(() -> {
+ mView.getRootView().dispatchTouchEvent(actionUpEvent);
+ actionUpEvent.recycle();
+ });
+ }
+ break;
+ }
+
postCheckForLongPress();
if (isStylusButtonPressed(ev)) {
triggerLongPress();
@@ -70,7 +94,8 @@
cancelLongPress();
break;
case MotionEvent.ACTION_MOVE:
- if (!Utilities.pointInView(mView, ev.getX(), ev.getY(), mSlop)) {
+ if (mIsInMouseRightClick
+ || !Utilities.pointInView(mView, ev.getX(), ev.getY(), mSlop)) {
cancelLongPress();
} else if (mPendingCheckForLongPress != null && isStylusButtonPressed(ev)) {
// Only trigger long press if it has not been cancelled before
@@ -98,9 +123,10 @@
}
/**
- * Cancels any pending long press
+ * Cancels any pending long press and right click
*/
public void cancelLongPress() {
+ mIsInMouseRightClick = false;
mHasPerformedLongPress = false;
clearCallbacks();
}
@@ -150,4 +176,14 @@
return event.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS
&& event.isButtonPressed(MotionEvent.BUTTON_SECONDARY);
}
+
+ /**
+ * Detect ACTION_DOWN or ACTION_MOVE from mouse right button. Note that we cannot detect
+ * ACTION_UP from mouse's right button because, in that case,
+ * {@link MotionEvent#getButtonState()} returns 0 for any mouse button (right, middle, right).
+ */
+ private static boolean isMouseRightClickDownOrMove(MotionEvent event) {
+ return event.isFromSource(InputDevice.SOURCE_MOUSE)
+ && ((event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0);
+ }
}
diff --git a/src/com/android/launcher3/DefaultLayoutParser.java b/src/com/android/launcher3/DefaultLayoutParser.java
index af13bea..c69ae4d 100644
--- a/src/com/android/launcher3/DefaultLayoutParser.java
+++ b/src/com/android/launcher3/DefaultLayoutParser.java
@@ -19,6 +19,7 @@
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 @@
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 @@
// 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);
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 1f97535..594d7cb 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -60,6 +60,7 @@
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 @@
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 @@
*/
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);
}
}
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index d002c2b..8ddbbaa 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -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.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.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 @@
}
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);
}
}
}
diff --git a/src/com/android/launcher3/Partner.java b/src/com/android/launcher3/Partner.java
deleted file mode 100644
index 2e27f32..0000000
--- a/src/com/android/launcher3/Partner.java
+++ /dev/null
@@ -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;
- }
- }
-}
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index e4e56a9..5c55b53 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -282,7 +282,7 @@
@Override
public int getHeaderBottom() {
if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) {
- return super.getHeaderBottom();
+ return super.getHeaderBottom() + mHeader.getClipTop();
}
return super.getHeaderBottom() + mSearchContainer.getBottom();
}
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
index 8e519c1..f308a25 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
@@ -58,6 +58,7 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.search.SearchAdapterProvider;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.keyboard.FocusedItemDecorator;
import com.android.launcher3.model.StringCache;
import com.android.launcher3.model.data.ItemInfo;
@@ -123,6 +124,7 @@
protected FloatingHeaderView mHeader;
private View mBottomSheetBackground;
private View mBottomSheetHandleArea;
+ @Nullable private View mSearchBarProtection;
protected boolean mUsingTabs;
private boolean mHasWorkApps;
@@ -363,6 +365,11 @@
return mSearchRecyclerView;
}
+ @Nullable
+ public View getSearchBarProtection() {
+ return mSearchBarProtection;
+ }
+
protected boolean isPersonalTab() {
return mViewPager == null || mViewPager.getNextPage() == 0;
}
@@ -410,6 +417,12 @@
});
mHeader = findViewById(R.id.all_apps_header);
+ mSearchBarProtection = findViewById(R.id.search_protection);
+ if (mSearchBarProtection != null) {
+ mSearchBarProtection.setBackgroundColor(mScrimColor);
+ mSearchBarProtection.setVisibility(
+ FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get() ? VISIBLE : GONE);
+ }
mSearchRecyclerView = findViewById(R.id.search_results_list_view);
mAH.get(AdapterHolder.SEARCH).setup(mSearchRecyclerView,
/* Filter out A-Z apps */ itemInfo -> false);
@@ -744,7 +757,7 @@
if (mHeaderPaint.getColor() != mScrimColor && mHeaderPaint.getColor() != 0) {
int bottom = getHeaderBottom();
FloatingHeaderView headerView = getFloatingHeaderView();
- if (!mUsingTabs) {
+ if (!mUsingTabs && !FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) {
// Add protection which is otherwise added when tabs scroll up.
bottom += headerView.getTabsAdditionalPaddingTop();
}
@@ -803,17 +816,6 @@
return mActivityContext.getDeviceProfile().isTablet ? mBottomSheetBackground : this;
}
- /**
- * Sets whether the view or its children should react to the window inset.
- * Used for when exiting all apps -> workspace and determines if window inset
- * should be applied.. ex) the work mode switch.
- */
- public void setApplyWindowInset(boolean shouldApplyWindowInset) {
- if (mWorkManager.getWorkModeSwitch() != null) {
- mWorkManager.getWorkModeSwitch().setApplyWindowInset(shouldApplyWindowInset);
- }
- }
-
protected void onInitializeRecyclerView(RecyclerView rv) {
rv.addOnScrollListener(mScrollListener);
}
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java
index 1cbb0f9..7fd3752 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderView.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java
@@ -364,6 +364,10 @@
onHeightUpdated();
}
+ public int getClipTop() {
+ return mHeaderClip.top;
+ }
+
public void reset(boolean animate) {
if (mAnimator.isStarted()) {
mAnimator.cancel();
diff --git a/src/com/android/launcher3/allapps/WorkModeSwitch.java b/src/com/android/launcher3/allapps/WorkModeSwitch.java
index 2272cdc..aadd0b5 100644
--- a/src/com/android/launcher3/allapps/WorkModeSwitch.java
+++ b/src/com/android/launcher3/allapps/WorkModeSwitch.java
@@ -19,7 +19,6 @@
import static com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.getTabWidth;
import android.content.Context;
-import android.graphics.Insets;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
@@ -27,6 +26,9 @@
import android.view.WindowInsets;
import android.widget.Button;
+import androidx.core.graphics.Insets;
+import androidx.core.view.WindowInsetsCompat;
+
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
import com.android.launcher3.R;
@@ -49,10 +51,10 @@
private static final int FLAG_PROFILE_TOGGLE_ONGOING = 1 << 3;
private final Rect mInsets = new Rect();
+ private final Rect mImeInsets = new Rect();
private int mFlags;
private boolean mWorkEnabled;
private boolean mOnWorkTab;
- private boolean mApplyWindowInset;
public WorkModeSwitch(Context context) {
this(context, null, 0);
@@ -89,12 +91,12 @@
@Override
public void setInsets(Rect insets) {
mInsets.set(insets);
+ updateTranslationY();
MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams();
if (lp != null) {
int bottomMargin = getResources().getDimensionPixelSize(R.dimen.work_fab_margin_bottom);
DeviceProfile dp = ActivityContext.lookupContext(getContext()).getDeviceProfile();
if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) {
- bottomMargin <<= 1; // Double margin to add space above search bar.
bottomMargin += dp.hotseatQsbHeight;
}
@@ -154,7 +156,6 @@
private void updateVisibility() {
clearAnimation();
- onApplyWindowInsets(getRootWindowInsets());
if (mWorkEnabled && mOnWorkTab) {
setFlag(FLAG_FADE_ONGOING);
setVisibility(VISIBLE);
@@ -170,16 +171,29 @@
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
- if (!Utilities.ATLEAST_R || !mApplyWindowInset) {
- return insets;
- }
- if (insets.isVisible(WindowInsets.Type.ime())) {
- Insets keyboardInsets = insets.getInsets(WindowInsets.Type.ime());
- setTranslationY(mInsets.bottom - keyboardInsets.bottom);
+ WindowInsetsCompat windowInsetsCompat =
+ WindowInsetsCompat.toWindowInsetsCompat(insets, this);
+ if (windowInsetsCompat.isVisible(WindowInsetsCompat.Type.ime())) {
+ setInsets(mImeInsets, windowInsetsCompat.getInsets(WindowInsetsCompat.Type.ime()));
} else {
- setTranslationY(0);
+ mImeInsets.setEmpty();
}
- return insets;
+ updateTranslationY();
+ return super.onApplyWindowInsets(insets);
+ }
+
+ private void updateTranslationY() {
+ setTranslationY(-mImeInsets.bottom);
+ }
+
+ @Override
+ public void setTranslationY(float translationY) {
+ // Always translate at least enough for nav bar insets.
+ super.setTranslationY(Math.min(translationY, -mInsets.bottom));
+ }
+
+ private void setInsets(Rect rect, Insets insets) {
+ rect.set(insets.left, insets.top, insets.right, insets.bottom);
}
@Override
@@ -199,8 +213,4 @@
private void removeFlag(int flag) {
mFlags &= ~flag;
}
-
- public void setApplyWindowInset(boolean applyWindowInset){
- mApplyWindowInset = applyWindowInset;
- }
}
diff --git a/src/com/android/launcher3/anim/KeyboardInsetAnimationCallback.java b/src/com/android/launcher3/anim/KeyboardInsetAnimationCallback.java
index 9d96365..3863dc1 100644
--- a/src/com/android/launcher3/anim/KeyboardInsetAnimationCallback.java
+++ b/src/com/android/launcher3/anim/KeyboardInsetAnimationCallback.java
@@ -53,10 +53,21 @@
mView.setTranslationY(mInitialTranslation);
return windowInsets;
}
- float progress = list.get(0).getInterpolatedFraction();
+ WindowInsetsAnimation animation = list.get(0);
- mView.setTranslationY(
- Utilities.mapRange(progress, mInitialTranslation, mTerminalTranslation));
+ if (animation.getDurationMillis() > -1) {
+ float progress = animation.getInterpolatedFraction();
+ mView.setTranslationY(
+ Utilities.mapRange(progress, mInitialTranslation, mTerminalTranslation));
+ } else {
+ // Manually controlled animation: Set translation to keyboard height.
+ int translationY = -windowInsets.getInsets(WindowInsets.Type.ime()).bottom;
+ if (mView.getParent() instanceof View) {
+ // Offset any translation of the parent (e.g. All Apps parallax).
+ translationY -= ((View) mView.getParent()).getTranslationY();
+ }
+ mView.setTranslationY(translationY);
+ }
return windowInsets;
}
@@ -73,6 +84,7 @@
@Override
public void onEnd(WindowInsetsAnimation animation) {
+ mView.setTranslationY(mTerminalTranslation);
if (mView instanceof KeyboardInsetListener) {
((KeyboardInsetListener) mView).onTranslationEnd();
}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 8363b68..5cab817 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -89,14 +89,6 @@
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");
@@ -371,6 +363,11 @@
"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) {
diff --git a/src/com/android/launcher3/dragndrop/BaseItemDragListener.java b/src/com/android/launcher3/dragndrop/BaseItemDragListener.java
index 6d127b3..981e3a6 100644
--- a/src/com/android/launcher3/dragndrop/BaseItemDragListener.java
+++ b/src/com/android/launcher3/dragndrop/BaseItemDragListener.java
@@ -74,7 +74,7 @@
}
@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);
diff --git a/src/com/android/launcher3/dragndrop/PinItemDragListener.java b/src/com/android/launcher3/dragndrop/PinItemDragListener.java
index fb924c1..af43ae8 100644
--- a/src/com/android/launcher3/dragndrop/PinItemDragListener.java
+++ b/src/com/android/launcher3/dragndrop/PinItemDragListener.java
@@ -72,8 +72,8 @@
}
@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);
}
diff --git a/src/com/android/launcher3/icons/LauncherIcons.java b/src/com/android/launcher3/icons/LauncherIcons.java
index 5508c49..57fa8a2 100644
--- a/src/com/android/launcher3/icons/LauncherIcons.java
+++ b/src/com/android/launcher3/icons/LauncherIcons.java
@@ -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 @@
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);
@@ -91,6 +96,18 @@
}
@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();
}
diff --git a/src/com/android/launcher3/icons/MonochromeIconFactory.java b/src/com/android/launcher3/icons/MonochromeIconFactory.java
new file mode 100644
index 0000000..511dcc7
--- /dev/null
+++ b/src/com/android/launcher3/icons/MonochromeIconFactory.java
@@ -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);
+ }
+}
diff --git a/src/com/android/launcher3/util/ActivityTracker.java b/src/com/android/launcher3/util/ActivityTracker.java
index 5f93a66..7af1a13 100644
--- a/src/com/android/launcher3/util/ActivityTracker.java
+++ b/src/com/android/launcher3/util/ActivityTracker.java
@@ -20,6 +20,8 @@
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 @@
*/
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 @@
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 @@
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 @@
* @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);
}
}
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index 9ca0dd1..8e3daf3 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -131,7 +131,10 @@
* 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
diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java
index 12e8b54..140440e 100644
--- a/src/com/android/launcher3/util/PackageManagerHelper.java
+++ b/src/com/android/launcher3/util/PackageManagerHelper.java
@@ -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.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.UserHandle;
import android.text.TextUtils;
import android.util.Log;
-import android.util.Pair;
import android.widget.Toast;
import androidx.annotation.NonNull;
@@ -296,25 +292,6 @@
}
/**
- * 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
* applications' manifest file.
diff --git a/src/com/android/launcher3/util/Partner.java b/src/com/android/launcher3/util/Partner.java
new file mode 100644
index 0000000..220ab56
--- /dev/null
+++ b/src/com/android/launcher3/util/Partner.java
@@ -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;
+ }
+}
diff --git a/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java b/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java
index a8753ed..9da7e0f 100644
--- a/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java
+++ b/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java
@@ -41,6 +41,7 @@
import org.junit.Assume;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -150,11 +151,13 @@
SimpleReorderCase.class.getSimpleName());
}
+ @Ignore
@Test
public void pushTest() throws ExecutionException, InterruptedException {
runTestCaseMap(PushReorderCase.TEST_BY_GRID_SIZE, PushReorderCase.class.getSimpleName());
}
+ @Ignore
@Test
public void fullReorder() throws ExecutionException, InterruptedException {
runTestCaseMap(FullReorderCase.TEST_BY_GRID_SIZE, FullReorderCase.class.getSimpleName());
diff --git a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
index 2c9785c..3f4a1c1 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
@@ -37,6 +37,7 @@
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -64,6 +65,7 @@
mAppWidgetManager = AppWidgetManager.getInstance(mTargetContext);
}
+ @Ignore
@Test
@PortraitLandscape
public void testWidgetConfig() throws Throwable {
diff --git a/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java b/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java
index 93329fa..9d5763b 100644
--- a/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java
+++ b/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java
@@ -38,6 +38,7 @@
import com.android.launcher3.util.Executors;
import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
+import org.junit.Ignore;
import org.junit.Test;
import java.util.ArrayDeque;
@@ -110,6 +111,7 @@
}
}
+ @Ignore
@Test
@ScreenRecord // b/260722220
public void testShortcutIconWithTheme() throws Exception {
diff --git a/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java b/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java
index bddb593..80e4116 100644
--- a/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java
+++ b/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java
@@ -55,7 +55,7 @@
}
/** 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),