Merge "Dismiss pip will fade task in and snap to it" into ub-launcher3-master
diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml
index 211e1ff..8f4d5be 100644
--- a/AndroidManifest-common.xml
+++ b/AndroidManifest-common.xml
@@ -44,6 +44,28 @@
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
+
+ <!--
+ Permissions required for read/write access to the workspace data. These permission name
+ should not conflict with that defined in other apps, as such an app should embed its package
+ name in the permissions. eq com.mypackage.permission.READ_SETTINGS
+ -->
+ <permission
+ android:name="${packageName}.permission.READ_SETTINGS"
+ android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+ android:protectionLevel="signatureOrSystem"
+ android:label="@string/permlab_read_settings"
+ android:description="@string/permdesc_read_settings"/>
+ <permission
+ android:name="${packageName}.permission.WRITE_SETTINGS"
+ android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+ android:protectionLevel="signatureOrSystem"
+ android:label="@string/permlab_write_settings"
+ android:description="@string/permdesc_write_settings"/>
+
+ <uses-permission android:name="${packageName}.permission.READ_SETTINGS" />
+ <uses-permission android:name="${packageName}.permission.WRITE_SETTINGS" />
+
<application
android:backupAgent="com.android.launcher3.LauncherBackupAgent"
android:fullBackupOnly="true"
@@ -118,5 +140,31 @@
android:name="com.android.launcher3.launcher_dump_provider"
android:value="com.android.launcher3.LauncherProvider" />
+ <!--
+ The settings provider contains Home's data, like the workspace favorites. The permissions
+ should be changed to what is defined above. The authorities should also be changed to
+ represent the package name.
+ -->
+ <provider
+ android:name="com.android.launcher3.LauncherProvider"
+ android:authorities="${packageName}.settings"
+ android:exported="true"
+ android:writePermission="${packageName}.permission.WRITE_SETTINGS"
+ android:readPermission="${packageName}.permission.READ_SETTINGS" />
+
+ <!--
+ The settings activity. To extend point settings_fragment_name to appropriate fragment class
+ -->
+ <activity
+ android:name="com.android.launcher3.SettingsActivity"
+ android:label="@string/settings_button_text"
+ android:theme="@android:style/Theme.DeviceDefault.Settings"
+ android:autoRemoveFromRecents="true">
+ <intent-filter>
+ <action android:name="android.intent.action.APPLICATION_PREFERENCES" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
</application>
</manifest>
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 3212980..4ac51ab 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -26,29 +26,6 @@
Refer comments around specific entries on how to extend individual components.
-->
- <!--
- Permissions required for read/write access to the workspace data. These permission name
- should not conflict with that defined in other apps, as such an app should embed its package
- name in the permissions. eq com.mypackage.permission.READ_SETTINGS
- -->
- <permission
- android:name="com.android.launcher3.permission.READ_SETTINGS"
- android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
- android:protectionLevel="signatureOrSystem"
- android:label="@string/permlab_read_settings"
- android:description="@string/permdesc_read_settings"/>
- <permission
- android:name="com.android.launcher3.permission.WRITE_SETTINGS"
- android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
- android:protectionLevel="signatureOrSystem"
- android:label="@string/permlab_write_settings"
- android:description="@string/permdesc_write_settings"/>
-
- <uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
- <uses-permission android:name="com.android.launcher.permission.WRITE_SETTINGS" />
- <uses-permission android:name="com.android.launcher3.permission.READ_SETTINGS" />
- <uses-permission android:name="com.android.launcher3.permission.WRITE_SETTINGS" />
-
<application
android:backupAgent="com.android.launcher3.LauncherBackupAgent"
android:fullBackupOnly="true"
@@ -86,31 +63,5 @@
</intent-filter>
</activity>
- <!--
- The settings activity. When extending keep the intent filter present
- -->
- <activity
- android:name="com.android.launcher3.SettingsActivity"
- android:label="@string/settings_button_text"
- android:theme="@android:style/Theme.DeviceDefault.Settings"
- android:autoRemoveFromRecents="true">
- <intent-filter>
- <action android:name="android.intent.action.APPLICATION_PREFERENCES" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- </activity>
-
- <!--
- The settings provider contains Home's data, like the workspace favorites. The permissions
- should be changed to what is defined above. The authorities should also be changed to
- represent the package name.
- -->
- <provider
- android:name="com.android.launcher3.LauncherProvider"
- android:authorities="com.android.launcher3.settings"
- android:exported="true"
- android:writePermission="com.android.launcher3.permission.WRITE_SETTINGS"
- android:readPermission="com.android.launcher3.permission.READ_SETTINGS" />
-
</application>
</manifest>
diff --git a/proguard.flags b/proguard.flags
index e401116..ddae07e 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -97,30 +97,19 @@
# support jar.
-keep class android.support.v7.widget.RecyclerView { *; }
-# LauncherAppTransitionManager
--keep class com.android.launcher3.LauncherAppTransitionManagerImpl {
+# Preference fragments
+-keep class ** extends android.preference.PreferenceFragment {
public <init>(...);
}
-# InstantAppResolver
--keep class com.android.quickstep.InstantAppResolverImpl {
- public <init>(...);
-}
-
-# MainProcessInitializer
--keep class com.android.quickstep.QuickstepProcessInitializer {
- public <init>(...);
-}
-
-# UserEventDispatcherExtension
--keep class com.android.quickstep.logging.UserEventDispatcherExtension {
+## Prevent obfuscating various overridable objects
+-keep class ** implements com.android.launcher3.util.ResourceBasedOverride {
public <init>(...);
}
-keep interface com.android.launcher3.userevent.nano.LauncherLogProto.** {
*;
}
-
-keep interface com.android.launcher3.model.nano.LauncherDumpProto.** {
*;
}
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index cb74855..74e0b1e 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -24,6 +24,7 @@
<uses-sdk android:targetSdkVersion="28" android:minSdkVersion="28"/>
<uses-permission android:name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS" />
+
<application
android:backupAgent="com.android.launcher3.LauncherBackupAgent"
android:fullBackupOnly="true"
@@ -59,10 +60,10 @@
android:resumeWhilePausing="true"
android:taskAffinity="" />
- <!-- Content provider to settings search -->
+ <!-- Content provider to settings search. The autority should be same as the packageName -->
<provider
android:name="com.android.quickstep.LauncherSearchIndexablesProvider"
- android:authorities="com.android.launcher3"
+ android:authorities="${packageName}"
android:grantUriPermissions="true"
android:multiprocess="true"
android:permission="android.permission.READ_SEARCH_INDEXABLES"
@@ -72,7 +73,6 @@
</intent-filter>
</provider>
-
<service
android:name="com.android.launcher3.uioverrides.dynamicui.WallpaperManagerCompatVL$ColorExtractionService"
tools:node="remove" />
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 17d5c60..49c4492 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -33,7 +33,7 @@
<!-- Launcher app transition -->
<dimen name="content_trans_y">50dp</dimen>
- <dimen name="springs_trans_y">-70dp</dimen>
+ <dimen name="workspace_trans_y">50dp</dimen>
<dimen name="closing_window_trans_y">115dp</dimen>
<dimen name="recents_empty_message_text_size">16sp</dimen>
diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
index 252e3ea..14633af 100644
--- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
@@ -16,7 +16,6 @@
package com.android.launcher3;
-import static android.view.View.TRANSLATION_Y;
import static com.android.launcher3.BaseActivity.INVISIBLE_ALL;
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_APP_TRANSITIONS;
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_PENDING_FLAGS;
@@ -28,10 +27,8 @@
import static com.android.launcher3.Utilities.postAsyncCallback;
import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE;
-import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.launcher3.anim.Interpolators.DEACCEL_1_7;
import static com.android.launcher3.anim.Interpolators.LINEAR;
-import static com.android.launcher3.anim.Interpolators.OSCILLATE;
import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_TRANSITIONS;
import static com.android.quickstep.TaskUtils.findTaskViewToLaunch;
import static com.android.quickstep.TaskUtils.getRecentsWindowAnimator;
@@ -57,7 +54,6 @@
import android.os.Handler;
import android.os.Looper;
import android.util.Pair;
-import android.util.Property;
import android.view.View;
import android.view.ViewGroup;
@@ -119,20 +115,12 @@
public static final int RECENTS_LAUNCH_DURATION = 336;
public static final int RECENTS_QUICKSCRUB_LAUNCH_DURATION = 300;
- private static final int LAUNCHER_RESUME_START_DELAY = 40;
+ private static final int LAUNCHER_RESUME_START_DELAY = 100;
private static final int CLOSING_TRANSITION_DURATION_MS = 250;
// Progress = 0: All apps is fully pulled up, Progress = 1: All apps is fully pulled down.
public static final float ALL_APPS_PROGRESS_OFF_SCREEN = 1.3059858f;
- private static final int APP_CLOSE_ROW_START_DELAY_MS = 8;
-
- // The sum of [slide, oscillate, and settle] should be <= LAUNCHER_RESUME_TOTAL_DURATION.
- private static final int LAUNCHER_RESUME_TOTAL_DURATION = 346;
- private static final int SPRING_SLIDE_DURATION = 166;
- private static final int SPRING_OSCILLATE_DURATION = 130;
- private static final int SPRING_SETTLE_DURATION = 50;
-
private final Launcher mLauncher;
private final DragLayer mDragLayer;
private final AlphaProperty mDragLayerAlpha;
@@ -141,8 +129,7 @@
private final boolean mIsRtl;
private final float mContentTransY;
- private final float mStartSlideTransY;
- private final float mEndSlideTransY;
+ private final float mWorkspaceTransY;
private final float mClosingWindowTransY;
private DeviceProfile mDeviceProfile;
@@ -172,9 +159,8 @@
Resources res = mLauncher.getResources();
mContentTransY = res.getDimensionPixelSize(R.dimen.content_trans_y);
+ mWorkspaceTransY = res.getDimensionPixelSize(R.dimen.workspace_trans_y);
mClosingWindowTransY = res.getDimensionPixelSize(R.dimen.closing_window_trans_y);
- mStartSlideTransY = res.getDimensionPixelSize(R.dimen.springs_trans_y);
- mEndSlideTransY = -mStartSlideTransY * 0.1f;
mLauncher.addOnDeviceProfileChangeListener(this);
registerRemoteAnimations();
@@ -786,33 +772,25 @@
});
} else {
AnimatorSet workspaceAnimator = new AnimatorSet();
+
+ mDragLayer.setTranslationY(-mWorkspaceTransY);;
+ workspaceAnimator.play(ObjectAnimator.ofFloat(mDragLayer, View.TRANSLATION_Y,
+ -mWorkspaceTransY, 0));
+
+ mDragLayerAlpha.setValue(0);
+ workspaceAnimator.play(ObjectAnimator.ofFloat(
+ mDragLayerAlpha, MultiValueAlpha.VALUE, 0, 1f));
+
workspaceAnimator.setStartDelay(LAUNCHER_RESUME_START_DELAY);
-
- ShortcutAndWidgetContainer currentPage = ((CellLayout) mLauncher.getWorkspace()
- .getChildAt(mLauncher.getWorkspace().getCurrentPage()))
- .getShortcutsAndWidgets();
-
- // Set up springs on workspace items.
- for (int i = currentPage.getChildCount() - 1; i >= 0; i--) {
- View child = currentPage.getChildAt(i);
- CellLayout.LayoutParams lp = ((CellLayout.LayoutParams) child.getLayoutParams());
- addStaggeredAnimationForView(child, workspaceAnimator, lp.cellY + lp.cellVSpan);
- }
-
- // Set up a spring for the shelf.
- if (!mLauncher.getDeviceProfile().isVerticalBarLayout()) {
- AllAppsTransitionController allAppsController = mLauncher.getAllAppsController();
- float shiftRange = allAppsController.getShiftRange();
- float slideStart = shiftRange / (shiftRange - mStartSlideTransY);
- float oscillateStart = shiftRange / (shiftRange - mEndSlideTransY);
-
- buildSpringAnimation(workspaceAnimator, allAppsController, ALL_APPS_PROGRESS,
- 0 /* startDelay */, slideStart, oscillateStart, 1f /* finalPosition */);
- }
+ workspaceAnimator.setDuration(333);
+ workspaceAnimator.setInterpolator(Interpolators.DEACCEL_1_7);
mDragLayer.getScrim().hideSysUiScrim(true);
+
// Pause page indicator animations as they lead to layer trashing.
mLauncher.getWorkspace().getPageIndicator().pauseAnimations();
+ mDragLayer.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+
workspaceAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -823,66 +801,6 @@
}
}
- /**
- * Adds an alpha/trans animator for {@param v}, with a start delay based on the view's row.
- *
- * @param v View in a ShortcutAndWidgetContainer.
- * @param row The bottom-most row that contains the view.
- */
- private void addStaggeredAnimationForView(View v, AnimatorSet outAnimator, int row) {
- // Invert the rows, because we stagger starting from the bottom of the screen.
- int invertedRow = LauncherAppState.getIDP(mLauncher).numRows - row + 1;
- long startDelay = (long) (invertedRow * APP_CLOSE_ROW_START_DELAY_MS);
-
- v.setAlpha(0);
- ObjectAnimator alpha = ObjectAnimator.ofFloat(v, View.ALPHA, 1f);
- alpha.setInterpolator(LINEAR);
- alpha.setDuration(SPRING_SLIDE_DURATION + SPRING_OSCILLATE_DURATION);
- alpha.setStartDelay(startDelay);
- outAnimator.play(alpha);
-
- buildSpringAnimation(outAnimator, v, TRANSLATION_Y, startDelay, mStartSlideTransY,
- mEndSlideTransY, 0f /* finalPosition */);
-
- outAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- v.setAlpha(1f);
- v.setTranslationY(0);
- }
- });
- }
-
- /**
- * Spring animations consists of three sequential animators: a slide, an oscillation, and
- * a settle.
- */
- private <T> void buildSpringAnimation(AnimatorSet outAnimator, T objectToSpring,
- Property<T, Float> property, long startDelay, float slideStart, float oscillateStart,
- float finalPosition) {
- // Ensures a clean hand-off between slide and oscillate.
- float slideEnd = Utilities.mapToRange(0, 0, 1f, oscillateStart, finalPosition, OSCILLATE);
-
- property.set(objectToSpring, slideStart);
-
- ObjectAnimator slideIn = ObjectAnimator.ofFloat(objectToSpring, property, slideStart,
- slideEnd);
- slideIn.setInterpolator(DEACCEL);
- slideIn.setStartDelay(startDelay);
- slideIn.setDuration(SPRING_SLIDE_DURATION);
-
- ObjectAnimator oscillate = ObjectAnimator.ofFloat(objectToSpring, property, oscillateStart,
- finalPosition);
- oscillate.setInterpolator(OSCILLATE);
- oscillate.setDuration(SPRING_OSCILLATE_DURATION);
-
- ObjectAnimator settle = ObjectAnimator.ofFloat(objectToSpring, property, finalPosition);
- settle.setInterpolator(LINEAR);
- settle.setDuration(SPRING_SETTLE_DURATION);
-
- outAnimator.playSequentially(slideIn, oscillate, settle);
- }
-
private void resetContentView() {
mLauncher.getWorkspace().getPageIndicator().skipAnimationsToEnd();
mDragLayerAlpha.setValue(1f);
diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
index 275075f..8fa6c49 100644
--- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java
+++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
@@ -23,6 +23,7 @@
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.states.RotationHelper.REQUEST_LOCK;
import static com.android.quickstep.TouchConsumer.INTERACTION_NORMAL;
import static com.android.quickstep.TouchConsumer.INTERACTION_QUICK_SCRUB;
import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
@@ -156,6 +157,10 @@
QuickScrubController controller = activity.<RecentsView>getOverviewPanel()
.getQuickScrubController();
controller.onQuickScrubStart(activityVisible && !fromState.overviewUi, this);
+
+ // For the duration of the gesture, lock the screen orientation to ensure that we do not
+ // rotate mid-quickscrub
+ activity.getRotationHelper().setStateHandlerRequest(REQUEST_LOCK);
}
@Override
diff --git a/quickstep/src/com/android/quickstep/LongSwipeHelper.java b/quickstep/src/com/android/quickstep/LongSwipeHelper.java
index 0785093..6b66ec8 100644
--- a/quickstep/src/com/android/quickstep/LongSwipeHelper.java
+++ b/quickstep/src/com/android/quickstep/LongSwipeHelper.java
@@ -20,17 +20,22 @@
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.quickstep.WindowTransformSwipeHandler.MAX_SWIPE_DURATION;
+import static com.android.quickstep.WindowTransformSwipeHandler.MIN_OVERSHOOT_DURATION;
import android.animation.ValueAnimator;
+import android.view.animation.Interpolator;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.AnimatorSetBuilder;
+import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.anim.Interpolators.OvershootParams;
import com.android.launcher3.uioverrides.PortraitStatesTouchController;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
@@ -89,7 +94,9 @@
}
public void end(float velocity, boolean isFling, Runnable callback) {
+ float velocityPxPerMs = velocity / 1000;
long duration = MAX_SWIPE_DURATION;
+ Interpolator interpolator = DEACCEL;
final float currentFraction = mAnimator.getProgressFraction();
final boolean toAllApps;
@@ -107,6 +114,16 @@
long expectedDuration = Math.abs(Math.round((endProgress - currentFraction)
* MAX_SWIPE_DURATION * SWIPE_DURATION_MULTIPLIER));
duration = Math.min(MAX_SWIPE_DURATION, expectedDuration);
+
+ if (blockedFling && !toAllApps) {
+ Interpolators.OvershootParams overshoot = new OvershootParams(currentFraction,
+ currentFraction, endProgress, velocityPxPerMs, (int) mMaxSwipeDistance);
+ duration = (overshoot.duration + duration);
+ duration = Utilities.boundToRange(duration, MIN_OVERSHOOT_DURATION,
+ MAX_SWIPE_DURATION);
+ interpolator = overshoot.interpolator;
+ endProgress = overshoot.end;
+ }
} else {
toAllApps = velocity < 0;
endProgress = toAllApps ? 1 : 0;
@@ -119,18 +136,16 @@
// we want the page's snap velocity to approximately match the velocity at
// which the user flings, so we scale the duration by a value near to the
// derivative of the scroll interpolator at zero, ie. 2.
- long baseDuration = Math.round(1000 * Math.abs(distanceToTravel / velocity));
+ long baseDuration = Math.round(Math.abs(distanceToTravel / velocityPxPerMs));
duration = Math.min(MAX_SWIPE_DURATION, 2 * baseDuration);
}
}
- if (blockedFling && !toAllApps) {
- duration *= LauncherAnimUtils.blockedFlingDurationFactor(0);
- }
final boolean finalIsFling = isFling;
mAnimator.setEndAction(() -> onSwipeAnimationComplete(toAllApps, finalIsFling, callback));
+
ValueAnimator animator = mAnimator.getAnimationPlayer();
- animator.setDuration(duration).setInterpolator(DEACCEL);
+ animator.setDuration(duration).setInterpolator(interpolator);
animator.setFloatValues(currentFraction, endProgress);
animator.start();
}
diff --git a/quickstep/src/com/android/quickstep/OverviewCallbacks.java b/quickstep/src/com/android/quickstep/OverviewCallbacks.java
index ac4a40b..ef9c5c0 100644
--- a/quickstep/src/com/android/quickstep/OverviewCallbacks.java
+++ b/quickstep/src/com/android/quickstep/OverviewCallbacks.java
@@ -18,20 +18,20 @@
import android.content.Context;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.ResourceBasedOverride;
/**
* Callbacks related to overview/quicksteps.
*/
-public class OverviewCallbacks {
+public class OverviewCallbacks implements ResourceBasedOverride {
private static OverviewCallbacks sInstance;
public static OverviewCallbacks get(Context context) {
Preconditions.assertUIThread();
if (sInstance == null) {
- sInstance = Utilities.getOverrideObject(OverviewCallbacks.class,
+ sInstance = Overrides.getObject(OverviewCallbacks.class,
context.getApplicationContext(), R.string.overview_callbacks_class);
}
return sInstance;
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index eff94fc..7094a53 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -197,14 +197,10 @@
}
public void onTip(int actionType, int viewType) {
- mMainThreadExecutor.execute(new Runnable() {
- @Override
- public void run() {
+ mMainThreadExecutor.execute(() ->
UserEventDispatcher.newInstance(mContext,
- new InvariantDeviceProfile(mContext).getDeviceProfile(mContext))
- .logActionTip(actionType, viewType);
- }
- });
+ InvariantDeviceProfile.INSTANCE.get(mContext).getDeviceProfile(mContext))
+ .logActionTip(actionType, viewType));
}
public ActivityControlHelper getActivityControlHelper() {
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index ed8b4d2..32079bf 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -42,7 +42,6 @@
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAnimationRunner;
-import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.badge.BadgeInfo;
@@ -131,21 +130,13 @@
}
private void initDeviceProfile() {
- // In case we are reusing IDP, create a copy so that we dont conflict with Launcher
+ DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(this).getDeviceProfile(this);
+
+ // In case we are reusing IDP, create a copy so that we don't conflict with Launcher
// activity.
- LauncherAppState appState = LauncherAppState.getInstanceNoCreate();
- if (isInMultiWindowModeCompat()) {
- InvariantDeviceProfile idp = appState == null
- ? new InvariantDeviceProfile(this) : appState.getInvariantDeviceProfile();
- DeviceProfile dp = idp.getDeviceProfile(this);
- mDeviceProfile = mRecentsRootView == null ? dp.copy(this)
- : dp.getMultiWindowProfile(this, mRecentsRootView.getLastKnownSize());
- } else {
- // If we are reusing the Invariant device profile, make a copy.
- mDeviceProfile = appState == null
- ? new InvariantDeviceProfile(this).getDeviceProfile(this)
- : appState.getInvariantDeviceProfile().getDeviceProfile(this).copy(this);
- }
+ mDeviceProfile = (mRecentsRootView != null) && isInMultiWindowModeCompat()
+ ? dp.getMultiWindowProfile(this, mRecentsRootView.getLastKnownSize())
+ : dp.copy(this);
onDeviceProfileInitiated();
}
diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
index 9d3ac6a..c272b1a 100644
--- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -22,22 +22,22 @@
import android.view.View;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.ResourceBasedOverride;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
/**
* Factory class to create and add an overlays on the TaskView
*/
-public class TaskOverlayFactory {
+public class TaskOverlayFactory implements ResourceBasedOverride {
private static TaskOverlayFactory sInstance;
public static TaskOverlayFactory get(Context context) {
Preconditions.assertUIThread();
if (sInstance == null) {
- sInstance = Utilities.getOverrideObject(TaskOverlayFactory.class,
+ sInstance = Overrides.getObject(TaskOverlayFactory.class,
context.getApplicationContext(), R.string.task_overlay_factory_class);
}
return sInstance;
diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
index ff3137d..3662633 100644
--- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -21,6 +21,7 @@
import static com.android.launcher3.Utilities.postAsyncCallback;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
import static com.android.quickstep.QuickScrubController.QUICK_SCRUB_FROM_APP_START_DURATION;
import static com.android.quickstep.TouchConsumer.INTERACTION_NORMAL;
import static com.android.quickstep.TouchConsumer.INTERACTION_QUICK_SCRUB;
@@ -56,7 +57,6 @@
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
@@ -163,6 +163,7 @@
public static final long MAX_SWIPE_DURATION = 350;
public static final long MIN_SWIPE_DURATION = 80;
+ public static final long MIN_OVERSHOOT_DURATION = 120;
public static final float MIN_PROGRESS_FOR_OVERVIEW = 0.5f;
private static final float SWIPE_DURATION_MULTIPLIER =
@@ -498,7 +499,8 @@
setStateOnUiThread(STATE_QUICK_SCRUB_START | STATE_GESTURE_COMPLETED);
// Start the window animation without waiting for launcher.
- animateToProgress(mCurrentShift.value, 1f, QUICK_SCRUB_FROM_APP_START_DURATION, LINEAR);
+ animateToProgress(mCurrentShift.value, 1f, QUICK_SCRUB_FROM_APP_START_DURATION, LINEAR,
+ true /* goingToHome */);
}
private void shiftAnimationDestinationForQuickscrub() {
@@ -608,10 +610,7 @@
public void onRecentsAnimationStart(RecentsAnimationControllerCompat controller,
RemoteAnimationTargetSet targets, Rect homeContentInsets, Rect minimizedHomeBounds) {
- LauncherAppState appState = LauncherAppState.getInstanceNoCreate();
- InvariantDeviceProfile idp = appState == null ?
- new InvariantDeviceProfile(mContext) : appState.getInvariantDeviceProfile();
- DeviceProfile dp = idp.getDeviceProfile(mContext);
+ DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(mContext).getDeviceProfile(mContext);
final Rect overviewStackBounds;
RemoteAnimationTargetCompat runningTaskTarget = targets.findTask(mRunningTaskId);
@@ -699,36 +698,46 @@
private void handleNormalGestureEnd(float endVelocity, boolean isFling) {
float velocityPxPerMs = endVelocity / 1000;
long duration = MAX_SWIPE_DURATION;
- final float endShift;
+ float currentShift = mCurrentShift.value;
+ final boolean goingToHome;
+ float endShift;
final float startShift;
- final Interpolator interpolator;
+ Interpolator interpolator = DEACCEL;
if (!isFling) {
- endShift = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW && mGestureStarted ? 1 : 0;
- long expectedDuration = Math.abs(Math.round((endShift - mCurrentShift.value)
+ goingToHome = currentShift >= MIN_PROGRESS_FOR_OVERVIEW && mGestureStarted;
+ endShift = goingToHome ? 1 : 0;
+ long expectedDuration = Math.abs(Math.round((endShift - currentShift)
* MAX_SWIPE_DURATION * SWIPE_DURATION_MULTIPLIER));
duration = Math.min(MAX_SWIPE_DURATION, expectedDuration);
- startShift = mCurrentShift.value;
- interpolator = DEACCEL;
+ startShift = currentShift;
+ interpolator = goingToHome ? OVERSHOOT_1_2 : DEACCEL;
} else {
- endShift = endVelocity < 0 ? 1 : 0;
- interpolator = endVelocity < 0
- ? Interpolators.overshootInterpolatorForVelocity(velocityPxPerMs, 2f)
- : DEACCEL;
+ goingToHome = endVelocity < 0;
+ endShift = goingToHome ? 1 : 0;
+ startShift = Utilities.boundToRange(currentShift - velocityPxPerMs
+ * SINGLE_FRAME_MS / mTransitionDragLength, 0, 1);
float minFlingVelocity = mContext.getResources()
.getDimension(R.dimen.quickstep_fling_min_velocity);
if (Math.abs(endVelocity) > minFlingVelocity && mTransitionDragLength > 0) {
- float distanceToTravel = (endShift - mCurrentShift.value) * mTransitionDragLength;
+ if (goingToHome) {
+ Interpolators.OvershootParams overshoot = new Interpolators.OvershootParams(
+ startShift, endShift, endShift, velocityPxPerMs, mTransitionDragLength);
+ endShift = overshoot.end;
+ interpolator = overshoot.interpolator;
+ duration = Utilities.boundToRange(overshoot.duration, MIN_OVERSHOOT_DURATION,
+ MAX_SWIPE_DURATION);
+ } else {
+ float distanceToTravel = (endShift - currentShift) * mTransitionDragLength;
- // we want the page's snap velocity to approximately match the velocity at
- // which the user flings, so we scale the duration by a value near to the
- // derivative of the scroll interpolator at zero, ie. 2.
- long baseDuration = Math.round(Math.abs(distanceToTravel / velocityPxPerMs));
- duration = Math.min(MAX_SWIPE_DURATION, 2 * baseDuration);
+ // we want the page's snap velocity to approximately match the velocity at
+ // which the user flings, so we scale the duration by a value near to the
+ // derivative of the scroll interpolator at zero, ie. 2.
+ long baseDuration = Math.round(Math.abs(distanceToTravel / velocityPxPerMs));
+ duration = Math.min(MAX_SWIPE_DURATION, 2 * baseDuration);
+ }
}
- startShift = Utilities.boundToRange(mCurrentShift.value - velocityPxPerMs
- * SINGLE_FRAME_MS / (mTransitionDragLength), 0, 1);
}
- animateToProgress(startShift, endShift, duration, interpolator);
+ animateToProgress(startShift, endShift, duration, interpolator, goingToHome);
}
private void doLogGesture(boolean toLauncher) {
@@ -754,14 +763,14 @@
/** Animates to the given progress, where 0 is the current app and 1 is overview. */
private void animateToProgress(float start, float end, long duration,
- Interpolator interpolator) {
+ Interpolator interpolator, boolean goingToHome) {
mRecentsAnimationWrapper.runOnInit(() -> animateToProgressInternal(start, end, duration,
- interpolator));
+ interpolator, goingToHome));
}
private void animateToProgressInternal(float start, float end, long duration,
- Interpolator interpolator) {
- mIsGoingToHome = Float.compare(end, 1) == 0;
+ Interpolator interpolator, boolean goingToHome) {
+ mIsGoingToHome = goingToHome;
ObjectAnimator anim = mCurrentShift.animateToValue(start, end).setDuration(duration);
anim.setInterpolator(interpolator);
anim.addListener(new AnimationSuccessListener() {
diff --git a/quickstep/src/com/android/quickstep/views/LauncherLayoutListener.java b/quickstep/src/com/android/quickstep/views/LauncherLayoutListener.java
index c149de5..61740d7 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherLayoutListener.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherLayoutListener.java
@@ -40,10 +40,6 @@
super(launcher, null);
mLauncher = launcher;
setVisibility(INVISIBLE);
-
- // For the duration of the gesture, lock the screen orientation to ensure that we do not
- // rotate mid-quickscrub
- launcher.getRotationHelper().setStateHandlerRequest(REQUEST_LOCK);
}
@Override
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index 6eb6854..098349a 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -175,9 +175,9 @@
params.width = sTempRect.width();
params.gravity = Gravity.LEFT;
setLayoutParams(params);
- setX(sTempRect.left - insets.left);
- setY(sTempRect.top + getResources().getDimension(R.dimen.task_thumbnail_top_margin)
- - insets.top);
+ setX(Math.round(sTempRect.left - insets.left));
+ setY(Math.round(sTempRect.top - insets.top
+ + getResources().getDimension(R.dimen.task_thumbnail_top_margin)));
}
private void animateOpen() {
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 5a8c6ca..2677b21 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -41,7 +41,7 @@
<string name="all_apps_search_market_message" msgid="1366263386197059176">"搜尋更多應用程式"</string>
<string name="notifications_header" msgid="1404149926117359025">"通知"</string>
<string name="long_press_shortcut_to_add" msgid="4524750017792716791">"按住捷徑即可選取。"</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"撳兩下之後撳住,就可以揀選捷徑或者用自訂嘅操作。"</string>
+ <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"連㩒兩下之後繼續㩒住,就可以揀選捷徑或者用自訂嘅操作。"</string>
<string name="out_of_space" msgid="4691004494942118364">"主畫面已無空間。"</string>
<string name="hotseat_out_of_space" msgid="7448809638125333693">"我的收藏寄存區沒有足夠空間"</string>
<string name="all_apps_button_label" msgid="8130441508702294465">"應用程式清單"</string>
diff --git a/res/values/config.xml b/res/values/config.xml
index f2d6c21..f462b9c 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -18,6 +18,9 @@
<!-- String representing the intent to delete a package.-->
<string name="delete_package_intent" translatable="false">#Intent;action=android.intent.action.DELETE;launchFlags=0x10800000;end</string>
+ <!-- String representing the fragment class for settings activity.-->
+ <string name="settings_fragment_name" translatable="false">com.android.launcher3.SettingsActivity$LauncherSettingsFragment</string>
+
<!-- Values for icon shape overrides. These should correspond to entries defined
in icon_shape_override_paths_names -->
<string-array translatable="false" name="icon_shape_override_paths_values">
@@ -92,9 +95,6 @@
<!-- Name of an app transition manager class. -->
<string name="app_transition_manager_class" translatable="false"></string>
- <!-- Name of a color extraction implementation class. -->
- <string name="color_extraction_impl_class" translatable="false"></string>
-
<!-- Name of a subclass of com.android.launcher3.util.InstantAppResolver. Can be empty. -->
<string name="instant_app_resolver_class" translatable="false"></string>
diff --git a/src/com/android/launcher3/AppFilter.java b/src/com/android/launcher3/AppFilter.java
index 923835a..9b6166f 100644
--- a/src/com/android/launcher3/AppFilter.java
+++ b/src/com/android/launcher3/AppFilter.java
@@ -3,10 +3,12 @@
import android.content.ComponentName;
import android.content.Context;
-public class AppFilter {
+import com.android.launcher3.util.ResourceBasedOverride;
+
+public class AppFilter implements ResourceBasedOverride {
public static AppFilter newInstance(Context context) {
- return Utilities.getOverrideObject(AppFilter.class, context, R.string.app_filter_class);
+ return Overrides.getObject(AppFilter.class, context, R.string.app_filter_class);
}
public boolean shouldShowApp(ComponentName app) {
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index 9dc3129..f496600 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -478,7 +478,8 @@
info.contentDescription = "";
info.usingLowResIcon = false;
} else {
- getTitleAndIcon(info, new ActivityInfoProvider(info.getIntent(), info.user),
+ Intent intent = info.getIntent();
+ getTitleAndIcon(info, () -> mLauncherApps.resolveActivity(intent, info.user),
true, useLowResIcon);
}
}
@@ -801,7 +802,7 @@
}
private static final class IconDB extends SQLiteCacheHelper {
- private final static int RELEASE_VERSION = 23;
+ private final static int RELEASE_VERSION = 24;
private final static String TABLE_NAME = "icons";
private final static String COLUMN_ROWID = "rowid";
@@ -869,22 +870,6 @@
}
}
- private class ActivityInfoProvider extends Provider<LauncherActivityInfo> {
-
- private final Intent mIntent;
- private final UserHandle mUser;
-
- public ActivityInfoProvider(Intent intent, UserHandle user) {
- mIntent = intent;
- mUser = user;
- }
-
- @Override
- public LauncherActivityInfo get() {
- return mLauncherApps.resolveActivity(mIntent, mUser);
- }
- }
-
/**
* Interface for receiving itemInfo with high-res icon.
*/
diff --git a/src/com/android/launcher3/IconProvider.java b/src/com/android/launcher3/IconProvider.java
index b469a8f..ed8d03c 100644
--- a/src/com/android/launcher3/IconProvider.java
+++ b/src/com/android/launcher3/IconProvider.java
@@ -5,14 +5,16 @@
import android.graphics.drawable.Drawable;
import android.os.Build;
+import com.android.launcher3.util.ResourceBasedOverride;
+
import java.util.Locale;
-public class IconProvider {
+public class IconProvider implements ResourceBasedOverride {
protected String mSystemState;
public static IconProvider newInstance(Context context) {
- IconProvider provider = Utilities.getOverrideObject(
+ IconProvider provider = Overrides.getObject(
IconProvider.class, context, R.string.icon_provider_class);
provider.updateSystemStateString(context);
return provider;
diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java
index fe8a841..b9d45fb 100644
--- a/src/com/android/launcher3/InstallShortcutReceiver.java
+++ b/src/com/android/launcher3/InstallShortcutReceiver.java
@@ -47,7 +47,6 @@
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.Preconditions;
-import com.android.launcher3.util.Provider;
import com.android.launcher3.util.Thunk;
import org.json.JSONException;
@@ -486,13 +485,10 @@
if (Looper.myLooper() == LauncherModel.getWorkerLooper()) {
app.getIconCache().getTitleAndIcon(si, activityInfo, false /* useLowResIcon */);
} else {
- app.getModel().updateAndBindShortcutInfo(new Provider<ShortcutInfo>() {
- @Override
- public ShortcutInfo get() {
- app.getIconCache().getTitleAndIcon(
- si, activityInfo, false /* useLowResIcon */);
- return si;
- }
+ app.getModel().updateAndBindShortcutInfo(() -> {
+ app.getIconCache().getTitleAndIcon(
+ si, activityInfo, false /* useLowResIcon */);
+ return si;
});
}
return Pair.create((ItemInfo) si, (Object) activityInfo);
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index f63cce5..22bc162 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -29,6 +29,8 @@
import android.view.WindowManager;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.util.ConfigMonitor;
+import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.Thunk;
import org.xmlpull.v1.XmlPullParser;
@@ -41,8 +43,12 @@
public class InvariantDeviceProfile {
- // This is a static that we use for the default icon size on a 4/5-inch phone
- private static float DEFAULT_ICON_SIZE_DP = 60;
+ // We do not need any synchronization for this variable as its only written on UI thread.
+ public static final MainThreadInitializedObject<InvariantDeviceProfile> INSTANCE =
+ new MainThreadInitializedObject<>((c) -> {
+ new ConfigMonitor(c).register();
+ return new InvariantDeviceProfile(c);
+ });
private static final float ICON_SIZE_DEFINED_IN_APP_DP = 48;
@@ -118,7 +124,7 @@
}
@TargetApi(23)
- public InvariantDeviceProfile(Context context) {
+ private InvariantDeviceProfile(Context context) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
DisplayMetrics dm = new DisplayMetrics();
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 3a8679e..9f16857 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -74,7 +74,6 @@
import android.widget.Toast;
import com.android.launcher3.DropTarget.DragObject;
-import com.android.launcher3.Workspace.ItemOperator;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.allapps.AllAppsTransitionController;
@@ -741,6 +740,8 @@
NotificationListener.removeNotificationsChangedListener();
getStateManager().moveToRestState();
+ UiFactory.onLauncherStateOrResumeChanged(this);
+
// Workaround for b/78520668, explicitly trim memory once UI is hidden
onTrimMemory(TRIM_MEMORY_UI_HIDDEN);
}
@@ -1050,12 +1051,7 @@
}
public FolderIcon findFolderIcon(final long folderIconId) {
- return (FolderIcon) mWorkspace.getFirstMatch(new ItemOperator() {
- @Override
- public boolean evaluate(ItemInfo info, View view) {
- return info != null && info.id == folderIconId;
- }
- });
+ return (FolderIcon) mWorkspace.getHomescreenIconByItemId(folderIconId);
}
/**
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index a46692b..5159de1 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -16,12 +16,13 @@
package com.android.launcher3;
+import static com.android.launcher3.SettingsActivity.NOTIFICATION_BADGING;
+
import android.content.ComponentName;
import android.content.ContentProviderClient;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.os.Looper;
import android.util.Log;
import com.android.launcher3.compat.LauncherAppsCompat;
@@ -29,21 +30,17 @@
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.notification.NotificationListener;
-import com.android.launcher3.util.ConfigMonitor;
+import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.SettingsObserver;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-
-import static com.android.launcher3.SettingsActivity.NOTIFICATION_BADGING;
-
public class LauncherAppState {
public static final String ACTION_FORCE_ROLOAD = "force-reload-launcher";
// We do not need any synchronization for this variable as its only written on UI thread.
- private static LauncherAppState INSTANCE;
+ private static final MainThreadInitializedObject<LauncherAppState> INSTANCE =
+ new MainThreadInitializedObject<>((c) -> new LauncherAppState(c));
private final Context mContext;
private final LauncherModel mModel;
@@ -53,27 +50,11 @@
private final SettingsObserver mNotificationBadgingObserver;
public static LauncherAppState getInstance(final Context context) {
- if (INSTANCE == null) {
- if (Looper.myLooper() == Looper.getMainLooper()) {
- INSTANCE = new LauncherAppState(context.getApplicationContext());
- } else {
- try {
- return new MainThreadExecutor().submit(new Callable<LauncherAppState>() {
- @Override
- public LauncherAppState call() throws Exception {
- return LauncherAppState.getInstance(context);
- }
- }).get();
- } catch (InterruptedException|ExecutionException e) {
- throw new RuntimeException(e);
- }
- }
- }
- return INSTANCE;
+ return INSTANCE.get(context);
}
public static LauncherAppState getInstanceNoCreate() {
- return INSTANCE;
+ return INSTANCE.getNoCreate();
}
public Context getContext() {
@@ -89,7 +70,7 @@
Preconditions.assertUIThread();
mContext = context;
- mInvariantDeviceProfile = new InvariantDeviceProfile(mContext);
+ mInvariantDeviceProfile = InvariantDeviceProfile.INSTANCE.get(mContext);
mIconCache = new IconCache(mContext, mInvariantDeviceProfile);
mWidgetCache = new WidgetPreviewLoader(mContext, mIconCache);
mModel = new LauncherModel(this, mIconCache, AppFilter.newInstance(mContext));
@@ -112,7 +93,6 @@
mContext.registerReceiver(mModel, filter);
UserManagerCompat.getInstance(mContext).enableAndResetCache();
- new ConfigMonitor(mContext).register();
if (!mContext.getResources().getBoolean(R.bool.notification_badging_enabled)) {
mNotificationBadgingObserver = null;
@@ -171,7 +151,7 @@
* Shorthand for {@link #getInvariantDeviceProfile()}
*/
public static InvariantDeviceProfile getIDP(Context context) {
- return LauncherAppState.getInstance(context).getInvariantDeviceProfile();
+ return InvariantDeviceProfile.INSTANCE.get(context);
}
private static LauncherProvider getLocalProvider(Context context) {
diff --git a/src/com/android/launcher3/LauncherAppTransitionManager.java b/src/com/android/launcher3/LauncherAppTransitionManager.java
index 4037a23..970e558 100644
--- a/src/com/android/launcher3/LauncherAppTransitionManager.java
+++ b/src/com/android/launcher3/LauncherAppTransitionManager.java
@@ -23,13 +23,15 @@
import android.graphics.drawable.Drawable;
import android.view.View;
+import com.android.launcher3.util.ResourceBasedOverride;
+
/**
* Manages the opening and closing app transitions from Launcher.
*/
-public class LauncherAppTransitionManager {
+public class LauncherAppTransitionManager implements ResourceBasedOverride {
public static LauncherAppTransitionManager newInstance(Context context) {
- return Utilities.getOverrideObject(LauncherAppTransitionManager.class,
+ return Overrides.getObject(LauncherAppTransitionManager.class,
context, R.string.app_transition_manager_class);
}
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 37538ae..19aa795 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -620,15 +620,12 @@
}
public void updateAndBindShortcutInfo(final ShortcutInfo si, final ShortcutInfoCompat info) {
- updateAndBindShortcutInfo(new Provider<ShortcutInfo>() {
- @Override
- public ShortcutInfo get() {
- si.updateFromDeepShortcutInfo(info, mApp.getContext());
- LauncherIcons li = LauncherIcons.obtain(mApp.getContext());
- li.createShortcutIcon(info).applyTo(si);
- li.recycle();
- return si;
- }
+ updateAndBindShortcutInfo(() -> {
+ si.updateFromDeepShortcutInfo(info, mApp.getContext());
+ LauncherIcons li = LauncherIcons.obtain(mApp.getContext());
+ li.createShortcutIcon(info).applyTo(si);
+ li.recycle();
+ return si;
});
}
diff --git a/src/com/android/launcher3/LauncherScroller.java b/src/com/android/launcher3/LauncherScroller.java
index a9b4955..e5042c4 100644
--- a/src/com/android/launcher3/LauncherScroller.java
+++ b/src/com/android/launcher3/LauncherScroller.java
@@ -18,541 +18,37 @@
import android.animation.TimeInterpolator;
import android.content.Context;
-import android.hardware.SensorManager;
-import android.os.Build;
-import android.view.ViewConfiguration;
-import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
+import android.widget.Scroller;
/**
- * This class differs from the framework {@link android.widget.Scroller} in that
- * you can modify the Interpolator post-construction.
+ * Extension of {@link android.widget.Scroller} with the ability to modify the
+ * Interpolator post-construction.
*/
-public class LauncherScroller {
- private int mMode;
+public class LauncherScroller extends Scroller {
- private int mStartX;
- private int mStartY;
- private int mFinalX;
- private int mFinalY;
+ private final InterpolatorWrapper mInterpolatorWrapper;
- private int mMinX;
- private int mMaxX;
- private int mMinY;
- private int mMaxY;
-
- private int mCurrX;
- private int mCurrY;
- private long mStartTime;
- private int mDuration;
- private float mDurationReciprocal;
- private float mDeltaX;
- private float mDeltaY;
- private boolean mFinished;
- private TimeInterpolator mInterpolator;
- private boolean mFlywheel;
-
- private float mVelocity;
- private float mCurrVelocity;
- private int mDistance;
-
- private float mFlingFriction = ViewConfiguration.getScrollFriction();
-
- private static final int DEFAULT_DURATION = 250;
- private static final int SCROLL_MODE = 0;
- private static final int FLING_MODE = 1;
-
- private static float DECELERATION_RATE = (float) (Math.log(0.78) / Math.log(0.9));
- private static final float INFLEXION = 0.35f; // Tension lines cross at (INFLEXION, 1)
- private static final float START_TENSION = 0.5f;
- private static final float END_TENSION = 1.0f;
- private static final float P1 = START_TENSION * INFLEXION;
- private static final float P2 = 1.0f - END_TENSION * (1.0f - INFLEXION);
-
- private static final int NB_SAMPLES = 100;
- private static final float[] SPLINE_POSITION = new float[NB_SAMPLES + 1];
- private static final float[] SPLINE_TIME = new float[NB_SAMPLES + 1];
-
- private float mDeceleration;
- private final float mPpi;
-
- // A context-specific coefficient adjusted to physical values.
- private float mPhysicalCoeff;
-
- static {
- float x_min = 0.0f;
- float y_min = 0.0f;
- for (int i = 0; i < NB_SAMPLES; i++) {
- final float alpha = (float) i / NB_SAMPLES;
-
- float x_max = 1.0f;
- float x, tx, coef;
- while (true) {
- x = x_min + (x_max - x_min) / 2.0f;
- coef = 3.0f * x * (1.0f - x);
- tx = coef * ((1.0f - x) * P1 + x * P2) + x * x * x;
- if (Math.abs(tx - alpha) < 1E-5) break;
- if (tx > alpha) x_max = x;
- else x_min = x;
- }
- SPLINE_POSITION[i] = coef * ((1.0f - x) * START_TENSION + x) + x * x * x;
-
- float y_max = 1.0f;
- float y, dy;
- while (true) {
- y = y_min + (y_max - y_min) / 2.0f;
- coef = 3.0f * y * (1.0f - y);
- dy = coef * ((1.0f - y) * START_TENSION + y) + y * y * y;
- if (Math.abs(dy - alpha) < 1E-5) break;
- if (dy > alpha) y_max = y;
- else y_min = y;
- }
- SPLINE_TIME[i] = coef * ((1.0f - y) * P1 + y * P2) + y * y * y;
- }
- SPLINE_POSITION[NB_SAMPLES] = SPLINE_TIME[NB_SAMPLES] = 1.0f;
-
- // This controls the viscous fluid effect (how much of it)
- sViscousFluidScale = 8.0f;
- // must be set to 1.0 (used in viscousFluid())
- sViscousFluidNormalize = 1.0f;
- sViscousFluidNormalize = 1.0f / viscousFluid(1.0f);
-
+ public LauncherScroller(Context context) {
+ this(context, new InterpolatorWrapper());
}
- private static float sViscousFluidScale;
- private static float sViscousFluidNormalize;
+ private LauncherScroller(Context context, InterpolatorWrapper interpolatorWrapper) {
+ super(context, interpolatorWrapper);
+ mInterpolatorWrapper = interpolatorWrapper;
+ }
public void setInterpolator(TimeInterpolator interpolator) {
- mInterpolator = interpolator;
+ mInterpolatorWrapper.interpolator = interpolator;
}
- /**
- * Create a Scroller with the default duration and interpolator.
- */
- public LauncherScroller(Context context) {
- this(context, null);
- }
+ private static class InterpolatorWrapper implements Interpolator {
- /**
- * Create a Scroller with the specified interpolator. If the interpolator is
- * null, the default (viscous) interpolator will be used. "Flywheel" behavior will
- * be in effect for apps targeting Honeycomb or newer.
- */
- public LauncherScroller(Context context, Interpolator interpolator) {
- this(context, interpolator,
- context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB);
- }
+ public TimeInterpolator interpolator;
- /**
- * Create a Scroller with the specified interpolator. If the interpolator is
- * null, the default (viscous) interpolator will be used. Specify whether or
- * not to support progressive "flywheel" behavior in flinging.
- */
- public LauncherScroller(Context context, Interpolator interpolator, boolean flywheel) {
- mFinished = true;
- mInterpolator = interpolator;
- mPpi = context.getResources().getDisplayMetrics().density * 160.0f;
- mDeceleration = computeDeceleration(ViewConfiguration.getScrollFriction());
- mFlywheel = flywheel;
-
- mPhysicalCoeff = computeDeceleration(0.84f); // look and feel tuning
- }
-
- /**
- * The amount of friction applied to flings. The default value
- * is {@link ViewConfiguration#getScrollFriction}.
- *
- * @param friction A scalar dimension-less value representing the coefficient of
- * friction.
- */
- public final void setFriction(float friction) {
- mDeceleration = computeDeceleration(friction);
- mFlingFriction = friction;
- }
-
- private float computeDeceleration(float friction) {
- return SensorManager.GRAVITY_EARTH // g (m/s^2)
- * 39.37f // inch/meter
- * mPpi // pixels per inch
- * friction;
- }
-
- /**
- *
- * Returns whether the scroller has finished scrolling.
- *
- * @return True if the scroller has finished scrolling, false otherwise.
- */
- public final boolean isFinished() {
- return mFinished;
- }
-
- /**
- * Force the finished field to a particular value.
- *
- * @param finished The new finished value.
- */
- public final void forceFinished(boolean finished) {
- mFinished = finished;
- }
-
- /**
- * Returns how long the scroll event will take, in milliseconds.
- *
- * @return The duration of the scroll in milliseconds.
- */
- public final int getDuration() {
- return mDuration;
- }
-
- /**
- * Returns the current X offset in the scroll.
- *
- * @return The new X offset as an absolute distance from the origin.
- */
- public final int getCurrX() {
- return mCurrX;
- }
-
- /**
- * Returns the current Y offset in the scroll.
- *
- * @return The new Y offset as an absolute distance from the origin.
- */
- public final int getCurrY() {
- return mCurrY;
- }
-
- /**
- * Returns the current velocity.
- *
- * @return The original velocity less the deceleration. Result may be
- * negative.
- */
- public float getCurrVelocity() {
- return mMode == FLING_MODE ?
- mCurrVelocity : mVelocity - mDeceleration * timePassed() / 2000.0f;
- }
-
- /**
- * Returns the start X offset in the scroll.
- *
- * @return The start X offset as an absolute distance from the origin.
- */
- public final int getStartX() {
- return mStartX;
- }
-
- /**
- * Returns the start Y offset in the scroll.
- *
- * @return The start Y offset as an absolute distance from the origin.
- */
- public final int getStartY() {
- return mStartY;
- }
-
- /**
- * Returns where the scroll will end. Valid only for "fling" scrolls.
- *
- * @return The final X offset as an absolute distance from the origin.
- */
- public final int getFinalX() {
- return mFinalX;
- }
-
- /**
- * Returns where the scroll will end. Valid only for "fling" scrolls.
- *
- * @return The final Y offset as an absolute distance from the origin.
- */
- public final int getFinalY() {
- return mFinalY;
- }
-
- /**
- * Call this when you want to know the new location. If it returns true,
- * the animation is not yet finished.
- */
- public boolean computeScrollOffset() {
- if (mFinished) {
- return false;
+ @Override
+ public float getInterpolation(float v) {
+ return interpolator == null ? v : interpolator.getInterpolation(v);
}
-
- int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
-
- if (timePassed < mDuration) {
- switch (mMode) {
- case SCROLL_MODE:
- float x = timePassed * mDurationReciprocal;
-
- if (mInterpolator == null)
- x = viscousFluid(x);
- else
- x = mInterpolator.getInterpolation(x);
-
- mCurrX = mStartX + Math.round(x * mDeltaX);
- mCurrY = mStartY + Math.round(x * mDeltaY);
- break;
- case FLING_MODE:
- final float t = (float) timePassed / mDuration;
- final int index = (int) (NB_SAMPLES * t);
- float distanceCoef = 1.f;
- float velocityCoef = 0.f;
- if (index < NB_SAMPLES) {
- final float t_inf = (float) index / NB_SAMPLES;
- final float t_sup = (float) (index + 1) / NB_SAMPLES;
- final float d_inf = SPLINE_POSITION[index];
- final float d_sup = SPLINE_POSITION[index + 1];
- velocityCoef = (d_sup - d_inf) / (t_sup - t_inf);
- distanceCoef = d_inf + (t - t_inf) * velocityCoef;
- }
-
- mCurrVelocity = velocityCoef * mDistance / mDuration * 1000.0f;
-
- mCurrX = mStartX + Math.round(distanceCoef * (mFinalX - mStartX));
- // Pin to mMinX <= mCurrX <= mMaxX
- mCurrX = Math.min(mCurrX, mMaxX);
- mCurrX = Math.max(mCurrX, mMinX);
-
- mCurrY = mStartY + Math.round(distanceCoef * (mFinalY - mStartY));
- // Pin to mMinY <= mCurrY <= mMaxY
- mCurrY = Math.min(mCurrY, mMaxY);
- mCurrY = Math.max(mCurrY, mMinY);
-
- if (mCurrX == mFinalX && mCurrY == mFinalY) {
- mFinished = true;
- }
-
- break;
- }
- }
- else {
- mCurrX = mFinalX;
- mCurrY = mFinalY;
- mFinished = true;
- }
- return true;
- }
-
- /**
- * Start scrolling by providing a starting point and the distance to travel.
- * The scroll will use the default value of 250 milliseconds for the
- * duration.
- *
- * @param startX Starting horizontal scroll offset in pixels. Positive
- * numbers will scroll the content to the left.
- * @param startY Starting vertical scroll offset in pixels. Positive numbers
- * will scroll the content up.
- * @param dx Horizontal distance to travel. Positive numbers will scroll the
- * content to the left.
- * @param dy Vertical distance to travel. Positive numbers will scroll the
- * content up.
- */
- public void startScroll(int startX, int startY, int dx, int dy) {
- startScroll(startX, startY, dx, dy, DEFAULT_DURATION);
- }
-
- /**
- * Start scrolling by providing a starting point, the distance to travel,
- * and the duration of the scroll.
- *
- * @param startX Starting horizontal scroll offset in pixels. Positive
- * numbers will scroll the content to the left.
- * @param startY Starting vertical scroll offset in pixels. Positive numbers
- * will scroll the content up.
- * @param dx Horizontal distance to travel. Positive numbers will scroll the
- * content to the left.
- * @param dy Vertical distance to travel. Positive numbers will scroll the
- * content up.
- * @param duration Duration of the scroll in milliseconds.
- */
- public void startScroll(int startX, int startY, int dx, int dy, int duration) {
- mMode = SCROLL_MODE;
- mFinished = false;
- mDuration = duration;
- mStartTime = AnimationUtils.currentAnimationTimeMillis();
- mStartX = startX;
- mStartY = startY;
- mFinalX = startX + dx;
- mFinalY = startY + dy;
- mDeltaX = dx;
- mDeltaY = dy;
- mDurationReciprocal = 1.0f / (float) mDuration;
- }
-
- /**
- * Start scrolling based on a fling gesture. The distance travelled will
- * depend on the initial velocity of the fling.
- *
- * @param startX Starting point of the scroll (X)
- * @param startY Starting point of the scroll (Y)
- * @param velocityX Initial velocity of the fling (X) measured in pixels per
- * second.
- * @param velocityY Initial velocity of the fling (Y) measured in pixels per
- * second
- * @param minX Minimum X value. The scroller will not scroll past this
- * point.
- * @param maxX Maximum X value. The scroller will not scroll past this
- * point.
- * @param minY Minimum Y value. The scroller will not scroll past this
- * point.
- * @param maxY Maximum Y value. The scroller will not scroll past this
- * point.
- */
- public void fling(int startX, int startY, int velocityX, int velocityY,
- int minX, int maxX, int minY, int maxY) {
- // Continue a scroll or fling in progress
- if (mFlywheel && !mFinished) {
- float oldVel = getCurrVelocity();
-
- float dx = (float) (mFinalX - mStartX);
- float dy = (float) (mFinalY - mStartY);
- float hyp = (float) Math.hypot(dx, dy);
-
- float ndx = dx / hyp;
- float ndy = dy / hyp;
-
- float oldVelocityX = ndx * oldVel;
- float oldVelocityY = ndy * oldVel;
- if (Math.signum(velocityX) == Math.signum(oldVelocityX) &&
- Math.signum(velocityY) == Math.signum(oldVelocityY)) {
- velocityX += oldVelocityX;
- velocityY += oldVelocityY;
- }
- }
-
- mMode = FLING_MODE;
- mFinished = false;
-
- float velocity = (float) Math.hypot(velocityX, velocityY);
-
- mVelocity = velocity;
- mDuration = getSplineFlingDuration(velocity);
- mStartTime = AnimationUtils.currentAnimationTimeMillis();
- mStartX = startX;
- mStartY = startY;
-
- float coeffX = velocity == 0 ? 1.0f : velocityX / velocity;
- float coeffY = velocity == 0 ? 1.0f : velocityY / velocity;
-
- double totalDistance = getSplineFlingDistance(velocity);
- mDistance = (int) (totalDistance * Math.signum(velocity));
-
- mMinX = minX;
- mMaxX = maxX;
- mMinY = minY;
- mMaxY = maxY;
-
- mFinalX = startX + (int) Math.round(totalDistance * coeffX);
- // Pin to mMinX <= mFinalX <= mMaxX
- mFinalX = Math.min(mFinalX, mMaxX);
- mFinalX = Math.max(mFinalX, mMinX);
-
- mFinalY = startY + (int) Math.round(totalDistance * coeffY);
- // Pin to mMinY <= mFinalY <= mMaxY
- mFinalY = Math.min(mFinalY, mMaxY);
- mFinalY = Math.max(mFinalY, mMinY);
- }
-
- private double getSplineDeceleration(float velocity) {
- return Math.log(INFLEXION * Math.abs(velocity) / (mFlingFriction * mPhysicalCoeff));
- }
-
- private int getSplineFlingDuration(float velocity) {
- final double l = getSplineDeceleration(velocity);
- final double decelMinusOne = DECELERATION_RATE - 1.0;
- return (int) (1000.0 * Math.exp(l / decelMinusOne));
- }
-
- private double getSplineFlingDistance(float velocity) {
- final double l = getSplineDeceleration(velocity);
- final double decelMinusOne = DECELERATION_RATE - 1.0;
- return mFlingFriction * mPhysicalCoeff * Math.exp(DECELERATION_RATE / decelMinusOne * l);
- }
-
- static float viscousFluid(float x)
- {
- x *= sViscousFluidScale;
- if (x < 1.0f) {
- x -= (1.0f - (float)Math.exp(-x));
- } else {
- float start = 0.36787944117f; // 1/e == exp(-1)
- x = 1.0f - (float)Math.exp(1.0f - x);
- x = start + x * (1.0f - start);
- }
- x *= sViscousFluidNormalize;
- return x;
- }
-
- /**
- * Stops the animation. Contrary to {@link #forceFinished(boolean)},
- * aborting the animating cause the scroller to move to the final x and y
- * position
- *
- * @see #forceFinished(boolean)
- */
- public void abortAnimation() {
- mCurrX = mFinalX;
- mCurrY = mFinalY;
- mFinished = true;
- }
-
- /**
- * Extend the scroll animation. This allows a running animation to scroll
- * further and longer, when used with {@link #setFinalX(int)} or {@link #setFinalY(int)}.
- *
- * @param extend Additional time to scroll in milliseconds.
- * @see #setFinalX(int)
- * @see #setFinalY(int)
- */
- public void extendDuration(int extend) {
- int passed = timePassed();
- mDuration = passed + extend;
- mDurationReciprocal = 1.0f / mDuration;
- mFinished = false;
- }
-
- /**
- * Returns the time elapsed since the beginning of the scrolling.
- *
- * @return The elapsed time in milliseconds.
- */
- public int timePassed() {
- return (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
- }
-
- /**
- * Sets the final position (X) for this scroller.
- *
- * @param newX The new X offset as an absolute distance from the origin.
- * @see #extendDuration(int)
- * @see #setFinalY(int)
- */
- public void setFinalX(int newX) {
- mFinalX = newX;
- mDeltaX = mFinalX - mStartX;
- mFinished = false;
- }
-
- /**
- * Sets the final position (Y) for this scroller.
- *
- * @param newY The new Y offset as an absolute distance from the origin.
- * @see #extendDuration(int)
- * @see #setFinalX(int)
- */
- public void setFinalY(int newY) {
- mFinalY = newY;
- mDeltaY = mFinalY - mStartY;
- mFinished = false;
- }
-
- /**
- * @hide
- */
- public boolean isScrollingInDirection(float xvel, float yvel) {
- return !mFinished && Math.signum(xvel) == Math.signum(mFinalX - mStartX) &&
- Math.signum(yvel) == Math.signum(mFinalY - mStartY);
}
}
diff --git a/src/com/android/launcher3/MainProcessInitializer.java b/src/com/android/launcher3/MainProcessInitializer.java
index 462eadb..0028f97 100644
--- a/src/com/android/launcher3/MainProcessInitializer.java
+++ b/src/com/android/launcher3/MainProcessInitializer.java
@@ -20,14 +20,15 @@
import com.android.launcher3.graphics.IconShapeOverride;
import com.android.launcher3.logging.FileLog;
+import com.android.launcher3.util.ResourceBasedOverride;
/**
* Utility class to handle one time initializations of the main process
*/
-public class MainProcessInitializer {
+public class MainProcessInitializer implements ResourceBasedOverride {
public static void initialize(Context context) {
- Utilities.getOverrideObject(
+ Overrides.getObject(
MainProcessInitializer.class, context, R.string.main_process_initializer_class)
.init(context);
}
diff --git a/src/com/android/launcher3/OverviewButtonClickListener.java b/src/com/android/launcher3/OverviewButtonClickListener.java
deleted file mode 100644
index dd670d2..0000000
--- a/src/com/android/launcher3/OverviewButtonClickListener.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.android.launcher3;
-
-import android.view.View;
-
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
-
-/**
- * A specialized listener for Overview buttons where both clicks and long clicks are logged
- * handled the same via {@link #handleViewClick(View)}.
- */
-public abstract class OverviewButtonClickListener implements View.OnClickListener,
- View.OnLongClickListener {
-
- private int mControlType; /** ControlType enum as defined in {@link Action.Touch} */
-
- public OverviewButtonClickListener(int controlType) {
- mControlType = controlType;
- }
-
- public void attachTo(View v) {
- v.setOnClickListener(this);
- v.setOnLongClickListener(this);
- }
-
- @Override
- public void onClick(View view) {
- if (shouldPerformClick(view)) {
- handleViewClick(view, Action.Touch.TAP);
- }
- }
-
- @Override
- public boolean onLongClick(View view) {
- if (shouldPerformClick(view)) {
- handleViewClick(view, Action.Touch.LONGPRESS);
- }
- return true;
- }
-
- private boolean shouldPerformClick(View view) {
- return !Launcher.getLauncher(view.getContext()).getWorkspace().isSwitchingState();
- }
-
- private void handleViewClick(View view, int action) {
- handleViewClick(view);
- Launcher.getLauncher(view.getContext()).getUserEventDispatcher()
- .logActionOnControl(action, mControlType);
- }
-
- public abstract void handleViewClick(View view);
-}
\ No newline at end of file
diff --git a/src/com/android/launcher3/SettingsActivity.java b/src/com/android/launcher3/SettingsActivity.java
index 32c198a..8589b7e 100644
--- a/src/com/android/launcher3/SettingsActivity.java
+++ b/src/com/android/launcher3/SettingsActivity.java
@@ -24,6 +24,7 @@
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
+import android.app.Fragment;
import android.app.FragmentManager;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -53,7 +54,8 @@
/**
* Settings activity for Launcher. Currently implements the following setting: Allow rotation
*/
-public class SettingsActivity extends Activity {
+public class SettingsActivity extends Activity
+ implements PreferenceFragment.OnPreferenceStartFragmentCallback {
private static final String ICON_BADGING_PREFERENCE_KEY = "pref_icon_badging";
/** Hidden field Settings.Secure.NOTIFICATION_BADGING */
@@ -71,9 +73,10 @@
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
+ Fragment f = Fragment.instantiate(this, getString(R.string.settings_fragment_name));
// Display the fragment as the main content.
getFragmentManager().beginTransaction()
- .replace(android.R.id.content, getNewFragment())
+ .replace(android.R.id.content, f)
.commit();
}
}
@@ -82,6 +85,22 @@
return new LauncherSettingsFragment();
}
+ @Override
+ public boolean onPreferenceStartFragment(
+ PreferenceFragment preferenceFragment, Preference pref) {
+ Fragment f = Fragment.instantiate(this, pref.getFragment(), pref.getExtras());
+ if (f instanceof DialogFragment) {
+ ((DialogFragment) f).show(getFragmentManager(), pref.getKey());
+ } else {
+ getFragmentManager()
+ .beginTransaction()
+ .replace(android.R.id.content, f)
+ .addToBackStack(pref.getKey())
+ .commit();
+ }
+ return true;
+ }
+
/**
* This fragment shows the launcher preferences.
*/
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 7fe8d35..8683b21 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -55,7 +55,6 @@
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashSet;
@@ -581,25 +580,6 @@
|| e.getCause() instanceof DeadObjectException;
}
- public static <T> T getOverrideObject(Class<T> clazz, Context context, int resId) {
- String className = context.getString(resId);
- if (!TextUtils.isEmpty(className)) {
- try {
- Class<?> cls = Class.forName(className);
- return (T) cls.getDeclaredConstructor(Context.class).newInstance(context);
- } catch (ClassNotFoundException | InstantiationException | IllegalAccessException
- | ClassCastException | NoSuchMethodException | InvocationTargetException e) {
- Log.e(TAG, "Bad overriden class", e);
- }
- }
-
- try {
- return clazz.newInstance();
- } catch (InstantiationException|IllegalAccessException e) {
- throw new RuntimeException(e);
- }
- }
-
/**
* Returns a HashSet with a single element. We use this instead of Collections.singleton()
* because HashSet ensures all operations, such as remove, are supported.
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index abba9c4..67bdd3b 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -3034,16 +3034,6 @@
});
}
- public View getViewForTag(final Object tag) {
- return getFirstMatch(new ItemOperator() {
-
- @Override
- public boolean evaluate(ItemInfo info, View v) {
- return info == tag;
- }
- });
- }
-
public LauncherAppWidgetHostView getWidgetForAppWidgetId(final int appWidgetId) {
return (LauncherAppWidgetHostView) getFirstMatch(new ItemOperator() {
diff --git a/src/com/android/launcher3/anim/Interpolators.java b/src/com/android/launcher3/anim/Interpolators.java
index 8a1abf4..675e26d 100644
--- a/src/com/android/launcher3/anim/Interpolators.java
+++ b/src/com/android/launcher3/anim/Interpolators.java
@@ -16,7 +16,10 @@
package com.android.launcher3.anim;
+import static com.android.launcher3.Utilities.SINGLE_FRAME_MS;
+
import android.graphics.Path;
+import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
@@ -45,6 +48,8 @@
public static final Interpolator DEACCEL_2_5 = new DecelerateInterpolator(2.5f);
public static final Interpolator DEACCEL_3 = new DecelerateInterpolator(3f);
+ public static final Interpolator ACCEL_DEACCEL = new AccelerateDecelerateInterpolator();
+
public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
public static final Interpolator AGGRESSIVE_EASE = new PathInterpolator(0.2f, 0f, 0f, 1f);
@@ -52,6 +57,9 @@
public static final Interpolator EXAGGERATED_EASE;
+ private static final int MIN_SETTLE_DURATION = 200;
+ private static final float OVERSHOOT_FACTOR = 0.9f;
+
static {
Path exaggeratedEase = new Path();
exaggeratedEase.moveTo(0, 0);
@@ -112,46 +120,18 @@
}
};
- /**
- * Interpolates using a particular section of the damped oscillation function.
- * The section is selected by scaling and shifting the function.
- */
- public static final Interpolator OSCILLATE = new Interpolator() {
-
- // Used to scale the oscillations horizontally
- private final float horizontalScale = 1f;
- // Used to shift the oscillations horizontally
- private final float horizontalShift = 0.5f;
- // Used to scale the oscillations vertically
- private final float verticalScale = 1f;
- // Used to shift the oscillations vertically
- private final float verticalShift = 1f;
-
- @Override
- public float getInterpolation(float t) {
- t = horizontalScale * (t + horizontalShift);
- return (float) ((verticalScale * (Math.exp(-t) * Math.cos(2 * Math.PI * t)))
- + verticalShift);
- }
- };
-
private static final float FAST_FLING_PX_MS = 10;
public static Interpolator scrollInterpolatorForVelocity(float velocity) {
return Math.abs(velocity) > FAST_FLING_PX_MS ? SCROLL : SCROLL_CUBIC;
}
- public static Interpolator overshootInterpolatorForVelocity(float velocity) {
- return overshootInterpolatorForVelocity(velocity, 1f);
- }
-
/**
* Create an OvershootInterpolator with tension directly related to the velocity (in px/ms).
* @param velocity The start velocity of the animation we want to overshoot.
- * @param dampFactor An optional factor to reduce the amount of tension (how far we overshoot).
*/
- public static Interpolator overshootInterpolatorForVelocity(float velocity, float dampFactor) {
- return new OvershootInterpolator(Math.min(Math.abs(velocity), 3f) / dampFactor);
+ public static Interpolator overshootInterpolatorForVelocity(float velocity) {
+ return new OvershootInterpolator(Math.min(Math.abs(velocity), 3f));
}
/**
@@ -183,4 +163,75 @@
float upperBound) {
return t -> Utilities.mapRange(interpolator.getInterpolation(t), lowerBound, upperBound);
}
-}
\ No newline at end of file
+
+ /**
+ * Computes parameters necessary for an overshoot effect.
+ */
+ public static class OvershootParams {
+ public Interpolator interpolator;
+ public float start;
+ public float end;
+ public long duration;
+
+ /**
+ * Given the input params, sets OvershootParams variables to be used by the caller.
+ * @param startProgress The progress from 0 to 1 that the overshoot starts from.
+ * @param overshootPastProgress The progress from 0 to 1 where we overshoot past (should
+ * either be equal to startProgress or endProgress, depending on if we want to
+ * overshoot immediately or only once we reach the end).
+ * @param endProgress The final progress from 0 to 1 that we will settle to.
+ * @param velocityPxPerMs The initial velocity that causes this overshoot.
+ * @param totalDistancePx The distance against which progress is calculated.
+ */
+ public OvershootParams(float startProgress, float overshootPastProgress,
+ float endProgress, float velocityPxPerMs, int totalDistancePx) {
+ velocityPxPerMs = Math.abs(velocityPxPerMs);
+ start = startProgress;
+ int startPx = (int) (start * totalDistancePx);
+ // Overshoot by about half a frame.
+ float overshootBy = OVERSHOOT_FACTOR * velocityPxPerMs *
+ SINGLE_FRAME_MS / totalDistancePx / 2;
+ overshootBy = Utilities.boundToRange(overshootBy, 0.02f, 0.15f);
+ end = overshootPastProgress + overshootBy;
+ int endPx = (int) (end * totalDistancePx);
+ int overshootDistance = endPx - startPx;
+ // Calculate deceleration necessary to reach overshoot distance.
+ // Formula: velocityFinal^2 = velocityInitial^2 + 2 * acceleration * distance
+ // 0 = v^2 + 2ad (velocityFinal == 0)
+ // a = v^2 / -2d
+ float decelerationPxPerMs = velocityPxPerMs * velocityPxPerMs / (2 * overshootDistance);
+ // Calculate time necessary to reach peak of overshoot.
+ // Formula: acceleration = velocity / time
+ // time = velocity / acceleration
+ duration = (long) (velocityPxPerMs / decelerationPxPerMs);
+
+ // Now that we're at the top of the overshoot, need to settle back to endProgress.
+ float settleDistance = end - endProgress;
+ int settleDistancePx = (int) (settleDistance * totalDistancePx);
+ // Calculate time necessary for the settle.
+ // Formula: distance = velocityInitial * time + 1/2 * acceleration * time^2
+ // d = 1/2at^2 (velocityInitial = 0, since we just stopped at the top)
+ // t = sqrt(2d/a)
+ // Above formula assumes constant acceleration. Since we use ACCEL_DEACCEL, we actually
+ // have acceleration to halfway then deceleration the rest. So the formula becomes:
+ // t = sqrt(d/a) * 2 (half the distance for accel, half for deaccel)
+ long settleDuration = (long) Math.sqrt(settleDistancePx / decelerationPxPerMs) * 4;
+
+ settleDuration = Math.max(MIN_SETTLE_DURATION, settleDuration);
+ // How much of the animation to devote to playing the overshoot (the rest is for settle).
+ float overshootFraction = (float) duration / (duration + settleDuration);
+ duration += settleDuration;
+ // Finally, create the interpolator, composed of two interpolators: an overshoot, which
+ // reaches end > 1, and then a settle to endProgress.
+ Interpolator overshoot = Interpolators.clampToProgress(DEACCEL, 0, overshootFraction);
+ // The settle starts at 1, where 1 is the top of the overshoot, and maps to a fraction
+ // such that final progress is endProgress. For example, if we overshot to 1.1 but want
+ // to end at 1, we need to map to 1/1.1.
+ Interpolator settle = Interpolators.clampToProgress(Interpolators.mapToProgress(
+ ACCEL_DEACCEL, 1, (endProgress - start) / (end - start)), overshootFraction, 1);
+ interpolator = t -> t <= overshootFraction
+ ? overshoot.getInterpolation(t)
+ : settle.getInterpolation(t);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/graphics/BitmapRenderer.java b/src/com/android/launcher3/graphics/BitmapRenderer.java
index 3d11c44..2a7f20e 100644
--- a/src/com/android/launcher3/graphics/BitmapRenderer.java
+++ b/src/com/android/launcher3/graphics/BitmapRenderer.java
@@ -23,32 +23,30 @@
import com.android.launcher3.Utilities;
-public class BitmapRenderer {
+/**
+ * Interface representing a bitmap draw operation.
+ */
+public interface BitmapRenderer {
- public static final boolean USE_HARDWARE_BITMAP = Utilities.ATLEAST_P;
+ boolean USE_HARDWARE_BITMAP = Utilities.ATLEAST_P;
- public static Bitmap createSoftwareBitmap(int width, int height, Renderer renderer) {
- Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- renderer.draw(new Canvas(result));
- return result;
- }
+ static Bitmap createSoftwareBitmap(int width, int height, BitmapRenderer renderer) {
+ Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ renderer.draw(new Canvas(result));
+ return result;
+ }
- @TargetApi(Build.VERSION_CODES.P)
- public static Bitmap createHardwareBitmap(int width, int height, Renderer renderer) {
- if (!USE_HARDWARE_BITMAP) {
- return createSoftwareBitmap(width, height, renderer);
- }
+ @TargetApi(Build.VERSION_CODES.P)
+ static Bitmap createHardwareBitmap(int width, int height, BitmapRenderer renderer) {
+ if (!USE_HARDWARE_BITMAP) {
+ return createSoftwareBitmap(width, height, renderer);
+ }
- Picture picture = new Picture();
- renderer.draw(picture.beginRecording(width, height));
- picture.endRecording();
- return Bitmap.createBitmap(picture);
- }
+ Picture picture = new Picture();
+ renderer.draw(picture.beginRecording(width, height));
+ picture.endRecording();
+ return Bitmap.createBitmap(picture);
+ }
- /**
- * Interface representing a bitmap draw operation.
- */
- public interface Renderer {
- void draw(Canvas out);
- }
+ void draw(Canvas out);
}
diff --git a/src/com/android/launcher3/graphics/DrawableFactory.java b/src/com/android/launcher3/graphics/DrawableFactory.java
index 34a4e2d..bbc013d 100644
--- a/src/com/android/launcher3/graphics/DrawableFactory.java
+++ b/src/com/android/launcher3/graphics/DrawableFactory.java
@@ -36,11 +36,12 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.AllAppsBackgroundDrawable;
+import com.android.launcher3.util.ResourceBasedOverride;
/**
* Factory for creating new drawables.
*/
-public class DrawableFactory {
+public class DrawableFactory implements ResourceBasedOverride {
private static final String TAG = "DrawableFactory";
@@ -52,7 +53,7 @@
public static DrawableFactory get(Context context) {
synchronized (LOCK) {
if (sInstance == null) {
- sInstance = Utilities.getOverrideObject(DrawableFactory.class,
+ sInstance = Overrides.getObject(DrawableFactory.class,
context.getApplicationContext(), R.string.drawable_factory_class);
}
return sInstance;
diff --git a/src/com/android/launcher3/graphics/LauncherIcons.java b/src/com/android/launcher3/graphics/LauncherIcons.java
index 09ea1ad..333fe59 100644
--- a/src/com/android/launcher3/graphics/LauncherIcons.java
+++ b/src/com/android/launcher3/graphics/LauncherIcons.java
@@ -340,7 +340,7 @@
if (Utilities.ATLEAST_OREO && icon instanceof AdaptiveIconDrawable) {
int offset = Math.max((int) Math.ceil(BLUR_FACTOR * textureWidth), Math.max(left, top));
int size = Math.max(width, height);
- icon.setBounds(offset, offset, offset + size, offset + size);
+ icon.setBounds(offset, offset, size - offset, size - offset);
} else {
icon.setBounds(left, top, left+width, top+height);
}
diff --git a/src/com/android/launcher3/logging/UserEventDispatcher.java b/src/com/android/launcher3/logging/UserEventDispatcher.java
index d1e1051..d9d3f68 100644
--- a/src/com/android/launcher3/logging/UserEventDispatcher.java
+++ b/src/com/android/launcher3/logging/UserEventDispatcher.java
@@ -51,6 +51,7 @@
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.InstantAppResolver;
import com.android.launcher3.util.LogConfig;
+import com.android.launcher3.util.ResourceBasedOverride;
import java.util.Locale;
import java.util.UUID;
@@ -61,7 +62,7 @@
*
* $ adb shell setprop log.tag.UserEvent VERBOSE
*/
-public class UserEventDispatcher {
+public class UserEventDispatcher implements ResourceBasedOverride {
private final static int MAXIMUM_VIEW_HIERARCHY_LEVEL = 5;
@@ -78,7 +79,7 @@
uuidStr = UUID.randomUUID().toString();
sharedPrefs.edit().putString(UUID_STORAGE, uuidStr).apply();
}
- UserEventDispatcher ued = Utilities.getOverrideObject(UserEventDispatcher.class,
+ UserEventDispatcher ued = Overrides.getObject(UserEventDispatcher.class,
context.getApplicationContext(), R.string.user_event_dispatcher_class);
ued.mDelegate = delegate;
ued.mIsInLandscapeMode = dp.isVerticalBarLayout();
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 06da843..e82c8f1 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -478,15 +478,11 @@
}
info = new ShortcutInfo(pinnedShortcut, context);
final ShortcutInfo finalInfo = info;
- Provider<Bitmap> fallbackIconProvider = new Provider<Bitmap>() {
- @Override
- public Bitmap get() {
- // If the pinned deep shortcut is no longer published,
- // use the last saved icon instead of the default.
- return c.loadIcon(finalInfo)
- ? finalInfo.iconBitmap : null;
- }
- };
+ // If the pinned deep shortcut is no longer published,
+ // use the last saved icon instead of the default.
+ Provider<Bitmap> fallbackIconProvider = () ->
+ c.loadIcon(finalInfo) ? finalInfo.iconBitmap : null;
+
LauncherIcons li = LauncherIcons.obtain(context);
li.createShortcutIcon(pinnedShortcut,
true /* badged */, fallbackIconProvider).applyTo(info);
diff --git a/src/com/android/launcher3/notification/NotificationListener.java b/src/com/android/launcher3/notification/NotificationListener.java
index b527b6a..ac5aaf8 100644
--- a/src/com/android/launcher3/notification/NotificationListener.java
+++ b/src/com/android/launcher3/notification/NotificationListener.java
@@ -197,7 +197,7 @@
mNotificationBadgingObserver = new SettingsObserver.Secure(getContentResolver()) {
@Override
public void onSettingChanged(boolean isNotificationBadgingEnabled) {
- if (!isNotificationBadgingEnabled) {
+ if (!isNotificationBadgingEnabled && sIsConnected) {
requestUnbind();
}
}
diff --git a/src/com/android/launcher3/util/FloatRange.java b/src/com/android/launcher3/util/FloatRange.java
deleted file mode 100644
index 12772f3..0000000
--- a/src/com/android/launcher3/util/FloatRange.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.util;
-
-/**
- * A mutable class for describing the range of two int values.
- */
-public class FloatRange {
-
- public float start, end;
-
- public FloatRange() { }
-
- public FloatRange(float s, float e) {
- set(s, e);
- }
-
- public void set(float s, float e) {
- start = s;
- end = e;
- }
-
- public boolean contains(float value) {
- return value >= start && value <= end;
- }
-}
diff --git a/src/com/android/launcher3/util/InstantAppResolver.java b/src/com/android/launcher3/util/InstantAppResolver.java
index 4485427..5dc7af8 100644
--- a/src/com/android/launcher3/util/InstantAppResolver.java
+++ b/src/com/android/launcher3/util/InstantAppResolver.java
@@ -23,7 +23,6 @@
import com.android.launcher3.AppInfo;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import java.util.Collections;
import java.util.List;
@@ -31,10 +30,10 @@
/**
* A wrapper class to access instant app related APIs.
*/
-public class InstantAppResolver {
+public class InstantAppResolver implements ResourceBasedOverride {
public static InstantAppResolver newInstance(Context context) {
- return Utilities.getOverrideObject(
+ return Overrides.getObject(
InstantAppResolver.class, context, R.string.instant_app_resolver_class);
}
diff --git a/src/com/android/launcher3/util/ItemInfoMatcher.java b/src/com/android/launcher3/util/ItemInfoMatcher.java
index daedaef..19cf6c1 100644
--- a/src/com/android/launcher3/util/ItemInfoMatcher.java
+++ b/src/com/android/launcher3/util/ItemInfoMatcher.java
@@ -18,7 +18,6 @@
import android.content.ComponentName;
import android.os.UserHandle;
-import android.util.SparseLongArray;
import com.android.launcher3.FolderInfo;
import com.android.launcher3.ItemInfo;
@@ -32,14 +31,14 @@
/**
* A utility class to check for {@link ItemInfo}
*/
-public abstract class ItemInfoMatcher {
+public interface ItemInfoMatcher {
- public abstract boolean matches(ItemInfo info, ComponentName cn);
+ boolean matches(ItemInfo info, ComponentName cn);
/**
* Filters {@param infos} to those satisfying the {@link #matches(ItemInfo, ComponentName)}.
*/
- public final HashSet<ItemInfo> filterItemInfos(Iterable<ItemInfo> infos) {
+ default HashSet<ItemInfo> filterItemInfos(Iterable<ItemInfo> infos) {
HashSet<ItemInfo> filtered = new HashSet<>();
for (ItemInfo i : infos) {
if (i instanceof ShortcutInfo) {
@@ -70,88 +69,43 @@
/**
* Returns a new matcher with returns true if either this or {@param matcher} returns true.
*/
- public ItemInfoMatcher or(final ItemInfoMatcher matcher) {
- final ItemInfoMatcher that = this;
- return new ItemInfoMatcher() {
- @Override
- public boolean matches(ItemInfo info, ComponentName cn) {
- return that.matches(info, cn) || matcher.matches(info, cn);
- }
- };
+ default ItemInfoMatcher or(ItemInfoMatcher matcher) {
+ return (info, cn) -> matches(info, cn) || matcher.matches(info, cn);
}
/**
* Returns a new matcher with returns true if both this and {@param matcher} returns true.
*/
- public ItemInfoMatcher and(final ItemInfoMatcher matcher) {
- final ItemInfoMatcher that = this;
- return new ItemInfoMatcher() {
- @Override
- public boolean matches(ItemInfo info, ComponentName cn) {
- return that.matches(info, cn) && matcher.matches(info, cn);
- }
- };
+ default ItemInfoMatcher and(ItemInfoMatcher matcher) {
+ return (info, cn) -> matches(info, cn) && matcher.matches(info, cn);
}
/**
* Returns a new matcher which returns the opposite boolean value of the provided
* {@param matcher}.
*/
- public static ItemInfoMatcher not(final ItemInfoMatcher matcher) {
- return new ItemInfoMatcher() {
- @Override
- public boolean matches(ItemInfo info, ComponentName cn) {
- return !matcher.matches(info, cn);
- }
- };
+ static ItemInfoMatcher not(ItemInfoMatcher matcher) {
+ return (info, cn) -> !matcher.matches(info, cn);
}
- public static ItemInfoMatcher ofUser(final UserHandle user) {
- return new ItemInfoMatcher() {
- @Override
- public boolean matches(ItemInfo info, ComponentName cn) {
- return info.user.equals(user);
- }
- };
+ static ItemInfoMatcher ofUser(UserHandle user) {
+ return (info, cn) -> info.user.equals(user);
}
- public static ItemInfoMatcher ofComponents(
- final HashSet<ComponentName> components, final UserHandle user) {
- return new ItemInfoMatcher() {
- @Override
- public boolean matches(ItemInfo info, ComponentName cn) {
- return components.contains(cn) && info.user.equals(user);
- }
- };
+ static ItemInfoMatcher ofComponents(HashSet<ComponentName> components, UserHandle user) {
+ return (info, cn) -> components.contains(cn) && info.user.equals(user);
}
- public static ItemInfoMatcher ofPackages(
- final HashSet<String> packageNames, final UserHandle user) {
- return new ItemInfoMatcher() {
- @Override
- public boolean matches(ItemInfo info, ComponentName cn) {
- return packageNames.contains(cn.getPackageName()) && info.user.equals(user);
- }
- };
+ static ItemInfoMatcher ofPackages(HashSet<String> packageNames, UserHandle user) {
+ return (info, cn) -> packageNames.contains(cn.getPackageName()) && info.user.equals(user);
}
- public static ItemInfoMatcher ofShortcutKeys(final HashSet<ShortcutKey> keys) {
- return new ItemInfoMatcher() {
- @Override
- public boolean matches(ItemInfo info, ComponentName cn) {
- return info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT &&
+ static ItemInfoMatcher ofShortcutKeys(HashSet<ShortcutKey> keys) {
+ return (info, cn) -> info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT &&
keys.contains(ShortcutKey.fromItemInfo(info));
- }
- };
}
- public static ItemInfoMatcher ofItemIds(
- final LongArrayMap<Boolean> ids, final Boolean matchDefault) {
- return new ItemInfoMatcher() {
- @Override
- public boolean matches(ItemInfo info, ComponentName cn) {
- return ids.get(info.id, matchDefault);
- }
- };
+ static ItemInfoMatcher ofItemIds(LongArrayMap<Boolean> ids, Boolean matchDefault) {
+ return (info, cn) -> ids.get(info.id, matchDefault);
}
}
diff --git a/src/com/android/launcher3/util/MainThreadInitializedObject.java b/src/com/android/launcher3/util/MainThreadInitializedObject.java
new file mode 100644
index 0000000..5747db1
--- /dev/null
+++ b/src/com/android/launcher3/util/MainThreadInitializedObject.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.util;
+
+import android.content.Context;
+import android.os.Looper;
+
+import com.android.launcher3.MainThreadExecutor;
+
+import java.util.concurrent.ExecutionException;
+
+/**
+ * Utility class for defining singletons which are initiated on main thread.
+ */
+public class MainThreadInitializedObject<T> {
+
+ private final ObjectProvider<T> mProvider;
+ private T mValue;
+
+ public MainThreadInitializedObject(ObjectProvider<T> provider) {
+ mProvider = provider;
+ }
+
+ public T get(Context context) {
+ if (mValue == null) {
+ if (Looper.myLooper() == Looper.getMainLooper()) {
+ mValue = mProvider.get(context.getApplicationContext());
+ } else {
+ try {
+ return new MainThreadExecutor().submit(() -> get(context)).get();
+ } catch (InterruptedException|ExecutionException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ return mValue;
+ }
+
+ public T getNoCreate() {
+ return mValue;
+ }
+
+ public interface ObjectProvider<T> {
+
+ T get(Context context);
+ }
+}
diff --git a/src/com/android/launcher3/util/Provider.java b/src/com/android/launcher3/util/Provider.java
index 1cdd8d6..4a54c0f 100644
--- a/src/com/android/launcher3/util/Provider.java
+++ b/src/com/android/launcher3/util/Provider.java
@@ -19,20 +19,15 @@
/**
* Utility class to allow lazy initialization of objects.
*/
-public abstract class Provider<T> {
+public interface Provider<T> {
/**
* Initializes and returns the object. This may contain expensive operations not suitable
* to UI thread.
*/
- public abstract T get();
+ T get();
- public static <T> Provider<T> of (final T value) {
- return new Provider<T>() {
- @Override
- public T get() {
- return value;
- }
- };
+ static <T> Provider<T> of (T value) {
+ return() -> value;
}
}
diff --git a/src/com/android/launcher3/util/ResourceBasedOverride.java b/src/com/android/launcher3/util/ResourceBasedOverride.java
new file mode 100644
index 0000000..e2c4992
--- /dev/null
+++ b/src/com/android/launcher3/util/ResourceBasedOverride.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.util;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * An interface to indicate that a class is dynamically loaded using resource overlay, hence its
+ * class name and constructor should be preserved by proguard
+ */
+public interface ResourceBasedOverride {
+
+ class Overrides {
+
+ private static final String TAG = "Overrides";
+
+ public static <T extends ResourceBasedOverride> T getObject(
+ Class<T> clazz, Context context, int resId) {
+ String className = context.getString(resId);
+ if (!TextUtils.isEmpty(className)) {
+ try {
+ Class<?> cls = Class.forName(className);
+ return (T) cls.getDeclaredConstructor(Context.class).newInstance(context);
+ } catch (ClassNotFoundException | InstantiationException | IllegalAccessException
+ | ClassCastException | NoSuchMethodException | InvocationTargetException e) {
+ Log.e(TAG, "Bad overriden class", e);
+ }
+ }
+
+ try {
+ return clazz.newInstance();
+ } catch (InstantiationException|IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/WallpaperColorInfo.java b/src_ui_overrides/com/android/launcher3/uioverrides/WallpaperColorInfo.java
index 2107094..56e3260 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/WallpaperColorInfo.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/WallpaperColorInfo.java
@@ -56,7 +56,7 @@
private WallpaperColorInfo(Context context) {
mWallpaperManager = WallpaperManagerCompat.getInstance(context);
mWallpaperManager.addOnColorsChangedListener(this);
- mExtractionType = ColorExtractionAlgorithm.newInstance(context);
+ mExtractionType = new ColorExtractionAlgorithm();
update(mWallpaperManager.getWallpaperColors(FLAG_SYSTEM));
}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/ColorExtractionAlgorithm.java b/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/ColorExtractionAlgorithm.java
index 0444212..21b324f 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/ColorExtractionAlgorithm.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/ColorExtractionAlgorithm.java
@@ -16,7 +16,6 @@
package com.android.launcher3.uioverrides.dynamicui;
-import android.content.Context;
import android.graphics.Color;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@@ -25,7 +24,6 @@
import android.util.Pair;
import android.util.Range;
-import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import java.util.Arrays;
@@ -37,11 +35,6 @@
**/
public class ColorExtractionAlgorithm {
- public static ColorExtractionAlgorithm newInstance(Context context) {
- return Utilities.getOverrideObject(ColorExtractionAlgorithm.class,
- context.getApplicationContext(), R.string.color_extraction_impl_class);
- }
-
private static final String TAG = "Tonal";
// Used for tonal palette fitting