diff options
Diffstat (limited to 'src/com/android')
7 files changed, 207 insertions, 52 deletions
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index cf20febd5..1ffe41bc6 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -16,6 +16,7 @@ package com.android.launcher3; +import android.content.ComponentName; import android.content.ContentProviderClient; import android.content.Context; import android.content.Intent; @@ -28,13 +29,17 @@ import com.android.launcher3.compat.PackageInstallerCompat; import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.dynamicui.ExtractionUtils; +import com.android.launcher3.notification.NotificationListener; import com.android.launcher3.util.ConfigMonitor; import com.android.launcher3.util.Preconditions; +import com.android.launcher3.util.SettingsObserver; import com.android.launcher3.util.TestingUtils; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; +import static com.android.launcher3.SettingsActivity.NOTIFICATION_BADGING; + public class LauncherAppState { public static final boolean PROFILE_STARTUP = FeatureFlags.IS_DOGFOOD_BUILD; @@ -47,7 +52,7 @@ public class LauncherAppState { private final IconCache mIconCache; private final WidgetPreviewLoader mWidgetCache; private final InvariantDeviceProfile mInvariantDeviceProfile; - + private final SettingsObserver mNotificationBadgingObserver; public static LauncherAppState getInstance(final Context context) { if (INSTANCE == null) { @@ -117,6 +122,23 @@ public class LauncherAppState { new ConfigMonitor(mContext).register(); ExtractionUtils.startColorExtractionServiceIfNecessary(mContext); + + if (!mContext.getResources().getBoolean(R.bool.notification_badging_enabled)) { + mNotificationBadgingObserver = null; + } else { + // Register an observer to rebind the notification listener when badging is re-enabled. + mNotificationBadgingObserver = new SettingsObserver.Secure( + mContext.getContentResolver()) { + @Override + public void onSettingChanged(boolean isNotificationBadgingEnabled) { + if (isNotificationBadgingEnabled) { + NotificationListener.requestRebind(new ComponentName( + mContext, NotificationListener.class)); + } + } + }; + mNotificationBadgingObserver.register(NOTIFICATION_BADGING); + } } /** @@ -127,6 +149,9 @@ public class LauncherAppState { final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(mContext); launcherApps.removeOnAppsChangedCallback(mModel); PackageInstallerCompat.getInstance(mContext).onStop(); + if (mNotificationBadgingObserver != null) { + mNotificationBadgingObserver.unregister(); + } } LauncherModel setLauncher(Launcher launcher) { diff --git a/src/com/android/launcher3/SettingsActivity.java b/src/com/android/launcher3/SettingsActivity.java index fa7769e3f..90463725f 100644 --- a/src/com/android/launcher3/SettingsActivity.java +++ b/src/com/android/launcher3/SettingsActivity.java @@ -26,17 +26,15 @@ import android.content.ContentResolver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; -import android.database.ContentObserver; import android.os.Bundle; -import android.os.Handler; import android.preference.ListPreference; import android.preference.Preference; import android.preference.PreferenceFragment; import android.provider.Settings; -import android.provider.Settings.System; import com.android.launcher3.graphics.IconShapeOverride; import com.android.launcher3.notification.NotificationListener; +import com.android.launcher3.util.SettingsObserver; import com.android.launcher3.views.ButtonPreference; /** @@ -45,8 +43,8 @@ import com.android.launcher3.views.ButtonPreference; public class SettingsActivity extends Activity { private static final String ICON_BADGING_PREFERENCE_KEY = "pref_icon_badging"; - // TODO: use Settings.Secure.NOTIFICATION_BADGING - private static final String NOTIFICATION_BADGING = "notification_badging"; + /** Hidden field Settings.Secure.NOTIFICATION_BADGING */ + public static final String NOTIFICATION_BADGING = "notification_badging"; /** Hidden field Settings.Secure.ENABLED_NOTIFICATION_LISTENERS */ private static final String NOTIFICATION_ENABLED_LISTENERS = "enabled_notification_listeners"; @@ -88,12 +86,9 @@ public class SettingsActivity extends Activity { // Register a content observer to listen for system setting changes while // this UI is active. - resolver.registerContentObserver( - Settings.System.getUriFor(System.ACCELEROMETER_ROTATION), - false, mRotationLockObserver); + mRotationLockObserver.register(Settings.System.ACCELEROMETER_ROTATION); // Initialize the UI once - mRotationLockObserver.onChange(true); rotationPref.setDefaultValue(Utilities.getAllowRotationDefaultValue(getActivity())); } @@ -107,13 +102,7 @@ public class SettingsActivity extends Activity { // Listen to system notification badge settings while this UI is active. mIconBadgingObserver = new IconBadgingObserver( iconBadgingPref, resolver, getFragmentManager()); - resolver.registerContentObserver( - Settings.Secure.getUriFor(NOTIFICATION_BADGING), - false, mIconBadgingObserver); - resolver.registerContentObserver( - Settings.Secure.getUriFor(NOTIFICATION_ENABLED_LISTENERS), - false, mIconBadgingObserver); - mIconBadgingObserver.onChange(true); + mIconBadgingObserver.register(NOTIFICATION_BADGING, NOTIFICATION_ENABLED_LISTENERS); } Preference iconShapeOverride = findPreference(IconShapeOverride.KEY_PREFERENCE); @@ -129,11 +118,11 @@ public class SettingsActivity extends Activity { @Override public void onDestroy() { if (mRotationLockObserver != null) { - getActivity().getContentResolver().unregisterContentObserver(mRotationLockObserver); + mRotationLockObserver.unregister(); mRotationLockObserver = null; } if (mIconBadgingObserver != null) { - getActivity().getContentResolver().unregisterContentObserver(mIconBadgingObserver); + mIconBadgingObserver.unregister(); mIconBadgingObserver = null; } super.onDestroy(); @@ -144,22 +133,18 @@ public class SettingsActivity extends Activity { * Content observer which listens for system auto-rotate setting changes, and enables/disables * the launcher rotation setting accordingly. */ - private static class SystemDisplayRotationLockObserver extends ContentObserver { + private static class SystemDisplayRotationLockObserver extends SettingsObserver.System { private final Preference mRotationPref; - private final ContentResolver mResolver; public SystemDisplayRotationLockObserver( Preference rotationPref, ContentResolver resolver) { - super(new Handler()); + super(resolver); mRotationPref = rotationPref; - mResolver = resolver; } @Override - public void onChange(boolean selfChange) { - boolean enabled = Settings.System.getInt(mResolver, - Settings.System.ACCELEROMETER_ROTATION, 1) == 1; + public void onSettingChanged(boolean enabled) { mRotationPref.setEnabled(enabled); mRotationPref.setSummary(enabled ? R.string.allow_rotation_desc : R.string.allow_rotation_blocked_desc); @@ -170,7 +155,7 @@ public class SettingsActivity extends Activity { * Content observer which listens for system badging setting changes, * and updates the launcher badging setting subtext accordingly. */ - private static class IconBadgingObserver extends ContentObserver + private static class IconBadgingObserver extends SettingsObserver.Secure implements Preference.OnPreferenceClickListener { private final ButtonPreference mBadgingPref; @@ -179,15 +164,14 @@ public class SettingsActivity extends Activity { public IconBadgingObserver(ButtonPreference badgingPref, ContentResolver resolver, FragmentManager fragmentManager) { - super(new Handler()); + super(resolver); mBadgingPref = badgingPref; mResolver = resolver; mFragmentManager = fragmentManager; } @Override - public void onChange(boolean selfChange) { - boolean enabled = Settings.Secure.getInt(mResolver, NOTIFICATION_BADGING, 1) == 1; + public void onSettingChanged(boolean enabled) { int summary = enabled ? R.string.icon_badging_desc_on : R.string.icon_badging_desc_off; boolean serviceEnabled = true; diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java index d4a7b9377..494cd5ac5 100644 --- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java +++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java @@ -111,12 +111,6 @@ public class AllAppsRecyclerView extends BaseRecyclerView implements LogContaine } @Override - public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent ev) { - mPullDetector.onTouchEvent(ev); - return super.onInterceptTouchEvent(rv, ev) || mOverScrollHelper.isInOverScroll(); - } - - @Override public boolean onTouchEvent(MotionEvent e) { mPullDetector.onTouchEvent(e); if (FeatureFlags.LAUNCHER3_PHYSICS && mSpringAnimationHandler != null) { @@ -287,7 +281,8 @@ public class AllAppsRecyclerView extends BaseRecyclerView implements LogContaine @Override public boolean onInterceptTouchEvent(MotionEvent e) { - boolean result = super.onInterceptTouchEvent(e); + mPullDetector.onTouchEvent(e); + boolean result = super.onInterceptTouchEvent(e) || mOverScrollHelper.isInOverScroll(); if (!result && e.getAction() == MotionEvent.ACTION_DOWN && mEmptySearchBackground != null && mEmptySearchBackground.getAlpha() > 0) { mEmptySearchBackground.setHotspot(e.getX(), e.getY()); @@ -562,11 +557,16 @@ public class AllAppsRecyclerView extends BaseRecyclerView implements LogContaine // and if one of the following criteria are met: // - User scrolls down when they're already at the bottom. // - User starts scrolling up, hits the top, and continues scrolling up. + boolean wasInOverScroll = mIsInOverScroll; mIsInOverScroll = !mScrollbar.isDraggingThumb() && ((!canScrollVertically(1) && displacement < 0) || (!canScrollVertically(-1) && isScrollingUp && mFirstScrollYOnScrollUp != 0)); - if (mIsInOverScroll) { + if (wasInOverScroll && !mIsInOverScroll) { + // Exit overscroll. This can happen when the user is in overscroll and then + // scrolls the opposite way. + reset(false /* shouldSpring */); + } else if (mIsInOverScroll) { if (Float.compare(mFirstDisplacement, 0) == 0) { // Because users can scroll before entering overscroll, we need to // subtract the amount where the user was not in overscroll. @@ -581,11 +581,15 @@ public class AllAppsRecyclerView extends BaseRecyclerView implements LogContaine @Override public void onDragEnd(float velocity, boolean fling) { + reset(mIsInOverScroll /* shouldSpring */); + } + + private void reset(boolean shouldSpring) { float y = getContentTranslationY(); if (Float.compare(y, 0) != 0) { - if (FeatureFlags.LAUNCHER3_PHYSICS) { + if (FeatureFlags.LAUNCHER3_PHYSICS && shouldSpring) { // We calculate our own velocity to give the springs the desired effect. - velocity = y / getDampedOverScroll(getHeight()) * MAX_RELEASE_VELOCITY; + float velocity = y / getDampedOverScroll(getHeight()) * MAX_RELEASE_VELOCITY; // We want to negate the velocity because we are moving to 0 from -1 due to the // downward motion. (y-axis -1 is above 0). mSpringAnimationHandler.animateToPositionWithVelocity(0, -1, -velocity); diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java index 6896b37d9..edfe0c15e 100644 --- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java +++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java @@ -283,7 +283,9 @@ public class AllAppsTransitionController implements TouchController, SwipeDetect } // Use a light system UI (dark icons) if all apps is behind at least half of the status bar. - boolean forceChange = shift <= mStatusBarHeight / 2; + boolean forceChange = FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS ? + shift <= mShiftRange / 4 : + shift <= mStatusBarHeight / 2; if (forceChange) { mLauncher.getSystemUiController().updateUiState( SystemUiController.UI_STATE_ALL_APPS, !mIsDarkTheme); diff --git a/src/com/android/launcher3/notification/NotificationListener.java b/src/com/android/launcher3/notification/NotificationListener.java index 73d89aa18..6a7098915 100644 --- a/src/com/android/launcher3/notification/NotificationListener.java +++ b/src/com/android/launcher3/notification/NotificationListener.java @@ -30,15 +30,20 @@ import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; import android.util.Pair; + import com.android.launcher3.LauncherModel; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.util.PackageUserKey; +import com.android.launcher3.util.SettingsObserver; + import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Set; +import static com.android.launcher3.SettingsActivity.NOTIFICATION_BADGING; + /** * A {@link NotificationListenerService} that sends updates to its * {@link NotificationsChangedListener} when notifications are posted or canceled, @@ -57,12 +62,14 @@ public class NotificationListener extends NotificationListenerService { private static NotificationListener sNotificationListenerInstance = null; private static NotificationsChangedListener sNotificationsChangedListener; private static boolean sIsConnected; + private static boolean sIsCreated; private final Handler mWorkerHandler; private final Handler mUiHandler; - private final Ranking mTempRanking = new Ranking(); + private SettingsObserver mNotificationBadgingObserver; + private final Handler.Callback mWorkerCallback = new Handler.Callback() { @Override public boolean handleMessage(Message message) { @@ -77,7 +84,7 @@ public class NotificationListener extends NotificationListenerService { List<StatusBarNotification> activeNotifications; if (sIsConnected) { try { - activeNotifications = filterNotifications(getActiveNotifications()); + activeNotifications = filterNotifications(getActiveNotifications()); } catch (SecurityException ex) { Log.e(TAG, "SecurityException: failed to fetch notifications"); activeNotifications = new ArrayList<StatusBarNotification>(); @@ -130,6 +137,28 @@ public class NotificationListener extends NotificationListenerService { sNotificationListenerInstance = this; } + @Override + public void onCreate() { + super.onCreate(); + sIsCreated = true; + mNotificationBadgingObserver = new SettingsObserver.Secure(getContentResolver()) { + @Override + public void onSettingChanged(boolean isNotificationBadgingEnabled) { + if (!isNotificationBadgingEnabled) { + requestUnbind(); + } + } + }; + mNotificationBadgingObserver.register(NOTIFICATION_BADGING); + } + + @Override + public void onDestroy() { + super.onDestroy(); + sIsCreated = false; + mNotificationBadgingObserver.unregister(); + } + public static @Nullable NotificationListener getInstanceIfConnected() { return sIsConnected ? sNotificationListenerInstance : null; } @@ -143,6 +172,11 @@ public class NotificationListener extends NotificationListenerService { NotificationListener notificationListener = getInstanceIfConnected(); if (notificationListener != null) { notificationListener.onNotificationFullRefresh(); + } else if (!sIsCreated && sNotificationsChangedListener != null) { + // User turned off badging globally, so we unbound this service; + // tell the listener that there are no notifications to remove dots. + sNotificationsChangedListener.onNotificationFullRefresh( + Collections.<StatusBarNotification>emptyList()); } } @@ -205,7 +239,7 @@ public class NotificationListener extends NotificationListenerService { .getActiveNotifications(NotificationKeyData.extractKeysOnly(keys) .toArray(new String[keys.size()])); return notifications == null - ? Collections.<StatusBarNotification>emptyList() : Arrays.asList(notifications); + ? Collections.<StatusBarNotification>emptyList() : Arrays.asList(notifications); } /** diff --git a/src/com/android/launcher3/util/SettingsObserver.java b/src/com/android/launcher3/util/SettingsObserver.java new file mode 100644 index 000000000..6baa24293 --- /dev/null +++ b/src/com/android/launcher3/util/SettingsObserver.java @@ -0,0 +1,100 @@ +/* + * 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; + +import android.content.ContentResolver; +import android.database.ContentObserver; +import android.os.Handler; +import android.provider.Settings; + +public interface SettingsObserver { + + /** + * Registers the content observer to call {@link #onSettingChanged(boolean)} when any of the + * passed settings change. The value passed to onSettingChanged() is based on the key setting. + */ + void register(String keySetting, String ... dependentSettings); + void unregister(); + void onSettingChanged(boolean keySettingEnabled); + + + abstract class Secure extends ContentObserver implements SettingsObserver { + private ContentResolver mResolver; + private String mKeySetting; + + public Secure(ContentResolver resolver) { + super(new Handler()); + mResolver = resolver; + } + + @Override + public void register(String keySetting, String ... dependentSettings) { + mKeySetting = keySetting; + mResolver.registerContentObserver( + Settings.Secure.getUriFor(mKeySetting), false, this); + for (String setting : dependentSettings) { + mResolver.registerContentObserver( + Settings.Secure.getUriFor(setting), false, this); + } + onChange(true); + } + + @Override + public void unregister() { + mResolver.unregisterContentObserver(this); + } + + @Override + public void onChange(boolean selfChange) { + super.onChange(selfChange); + onSettingChanged(Settings.Secure.getInt(mResolver, mKeySetting, 1) == 1); + } + } + + abstract class System extends ContentObserver implements SettingsObserver { + private ContentResolver mResolver; + private String mKeySetting; + + public System(ContentResolver resolver) { + super(new Handler()); + mResolver = resolver; + } + + @Override + public void register(String keySetting, String ... dependentSettings) { + mKeySetting = keySetting; + mResolver.registerContentObserver( + Settings.System.getUriFor(mKeySetting), false, this); + for (String setting : dependentSettings) { + mResolver.registerContentObserver( + Settings.System.getUriFor(setting), false, this); + } + onChange(true); + } + + @Override + public void unregister() { + mResolver.unregisterContentObserver(this); + } + + @Override + public void onChange(boolean selfChange) { + super.onChange(selfChange); + onSettingChanged(Settings.System.getInt(mResolver, mKeySetting, 1) == 1); + } + } +} diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java index 0b4bf628e..01101ac74 100644 --- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java +++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java @@ -88,7 +88,8 @@ public class WidgetsBottomSheet extends AbstractFloatingView implements Insettab mScrollInterpolator = new SwipeDetector.ScrollInterpolator(); mInsets = new Rect(); mSwipeDetector = new SwipeDetector(context, this, SwipeDetector.VERTICAL); - mGradientBackground = (GradientView) mLauncher.findViewById(R.id.gradient_bg); + mGradientBackground = (GradientView) mLauncher.getLayoutInflater().inflate( + R.layout.gradient_bg, mLauncher.getDragLayer(), false); } @Override @@ -106,6 +107,8 @@ public class WidgetsBottomSheet extends AbstractFloatingView implements Insettab onWidgetsBound(); + mLauncher.getDragLayer().addView(mGradientBackground); + mGradientBackground.setVisibility(VISIBLE); mLauncher.getDragLayer().addView(this); measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); setTranslationY(mTranslationYClosed); @@ -212,11 +215,8 @@ public class WidgetsBottomSheet extends AbstractFloatingView implements Insettab mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - mIsOpen = false; mSwipeDetector.finishedScrolling(); - ((ViewGroup) getParent()).removeView(WidgetsBottomSheet.this); - mLauncher.getSystemUiController().updateUiState( - SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET, 0); + onCloseComplete(); } }); mOpenCloseAnimator.setInterpolator(mSwipeDetector.isIdleState() @@ -224,12 +224,18 @@ public class WidgetsBottomSheet extends AbstractFloatingView implements Insettab mOpenCloseAnimator.start(); } else { setTranslationY(mTranslationYClosed); - mLauncher.getSystemUiController().updateUiState( - SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET, 0); - mIsOpen = false; + onCloseComplete(); } } + private void onCloseComplete() { + mIsOpen = false; + mLauncher.getDragLayer().removeView(mGradientBackground); + mLauncher.getDragLayer().removeView(WidgetsBottomSheet.this); + mLauncher.getSystemUiController().updateUiState( + SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET, 0); + } + @Override protected boolean isOfType(@FloatingViewType int type) { return (type & TYPE_WIDGETS_BOTTOM_SHEET) != 0; |