From 5618f90cd7178838a53c6181eed7b67d86327c7c Mon Sep 17 00:00:00 2001 From: Pranav Vashi Date: Sat, 17 Sep 2022 17:29:13 +0530 Subject: [PATCH 01/19] DerpLauncher: Bring back QuickSpace events * This is wholesome squash of work done in 11.0 of crDroid Home * History commits - https://github.com/crdroidandroid/android_packages_apps_Launcher3/commits/11.0/src/com/android/launcher3/quickspace Squashed with: Author: minaripenguin Date: Mon Dec 26 14:16:30 2022 +0800 DerpLauncher: Quickspace: Apply at a glance widget design Author: Pranav Vashi Date: Thu Sep 28 22:41:45 2023 +0530 DerpLauncher: Quickspace: Do not pollute with greetings and fix NPE Signed-off-by: Pranav Vashi Author: Pranav Vashi Date: Fri Sep 29 08:05:05 2023 +0530 DerpLauncher: Quickspace: Improve loading routines Signed-off-by: Pranav Vashi Author: Pranav Vashi Date: Fri Sep 29 12:21:47 2023 +0530 DerpLauncher: Quickspace: Do not exceed 3 lines Signed-off-by: Pranav Vashi Author: Pranav Vashi Date: Fri Sep 29 18:26:10 2023 +0530 DerpLauncher: Quickspace: Rewrite all the greetings * Who tf drinks so much water? Signed-off-by: Pranav Vashi Author: Pranav Vashi Date: Sun Nov 26 20:33:21 2023 +0530 DerpLauncher: Quickspace: Make weather condition text optional Signed-off-by: Pranav Vashi Author: El Dainosor Date: Tue Dec 12 12:54:36 2023 -0300 DerpLauncher: Quickspace: Improve quick events Avoid some events being triggered after being disabled (for example, now playing or even the PSA). Also, fix the logic behind the lucky magic messages in PSA (it was broken on lucky number) Author: El Dainosor Date: Tue Dec 12 15:18:34 2023 -0300 quickspace: Remove the now playing icon on the right reason: We not just play music on our devices, at the same time, it's just being used for one event. Author: El Dainosor Date: Thu Dec 14 11:57:35 2023 -0300 DerpLauncher: Reorganize at a glance settings Author: jenslody Date: Fri Feb 16 15:34:20 2024 +0100 DerpLauncher: Never disable weather settings If Omnijaws is disabled in settings, we haven't been able to reenable it. It was unreachable, because it depended on the show-weather-switch, which depends on Omnijaws beeing activated. WIth keeping the settings enabled, we can switch Omnijaws on again. Signed-off-by: jenslody Author: Rizky Benggolo Date: Sun Feb 18 06:06:03 2024 +0000 DerpLauncher: Improve quickspace strings Author: Rizky Benggolo Date: Sun Feb 4 10:35:25 2024 +0000 DerpLauncher: Quickspace: A little layout improvement Co-authored-by: Chris Co-authored-by: El Dainosor Co-authored-by: Ali B Co-authored-by: Till Kottmann Co-authored-by: minaripenguin Co-authored-by: Rizky Benggolo Co-authored-by: jenslody Signed-off-by: Pranav Vashi --- AndroidManifest-common.xml | 6 + ...pp_whitelist_com.android.launcher3-ext.xml | 3 + res/drawable/bg_quickspace.xml | 17 + res/drawable/ic_music_note_24dp.xml | 10 + res/drawable/ic_quickspace_derp.xml | 18 + res/drawable/ic_quickspace_evening.xml | 8 + res/drawable/ic_quickspace_midnight.xml | 7 + res/drawable/ic_quickspace_morning.xml | 8 + res/layout/quickspace_alternate_double.xml | 209 +++++++++ res/layout/quickspace_doubleline.xml | 135 ++++++ ...reserved_container_alternate_workspace.xml | 34 ++ res/layout/reserved_container_workspace.xml | 35 ++ res/values/derp_config.xml | 3 + res/values/derp_dimens.xml | 6 + res/values/derp_strings.xml | 210 +++++++++ res/values/derp_styles.xml | 16 + res/xml/launcher_home_screen_preferences.xml | 76 ++++ .../android/launcher3/AutoInstallsLayout.java | 21 - .../launcher3/DefaultLayoutParser.java | 1 - src/com/android/launcher3/Launcher.java | 30 +- src/com/android/launcher3/ModelCallbacks.kt | 11 +- src/com/android/launcher3/Utilities.java | 58 +++ src/com/android/launcher3/Workspace.java | 11 +- .../launcher3/config/FeatureFlags.java | 2 +- .../graphics/LauncherPreviewRenderer.java | 4 +- .../android/launcher3/model/BgDataModel.java | 5 +- .../launcher3/model/DatabaseHelper.java | 2 +- .../model/GridSizeMigrationUtil.java | 2 +- .../android/launcher3/model/LoaderCursor.java | 2 +- .../android/launcher3/model/LoaderTask.java | 15 +- .../model/WorkspaceItemSpaceFinder.java | 3 +- .../quickspace/QuickEventsController.java | 428 ++++++++++++++++++ .../launcher3/quickspace/QuickSpaceView.java | 291 ++++++++++++ .../quickspace/QuickspaceController.java | 295 ++++++++++++ .../receivers/QuickSpaceActionReceiver.java | 96 ++++ .../quickspace/views/DateTextView.java | 94 ++++ .../views/DoubleShadowTextView.java | 53 +++ .../settings/SettingsHomescreen.java | 19 + 38 files changed, 2179 insertions(+), 65 deletions(-) create mode 100644 res/drawable/bg_quickspace.xml create mode 100644 res/drawable/ic_music_note_24dp.xml create mode 100644 res/drawable/ic_quickspace_derp.xml create mode 100644 res/drawable/ic_quickspace_evening.xml create mode 100644 res/drawable/ic_quickspace_midnight.xml create mode 100644 res/drawable/ic_quickspace_morning.xml create mode 100644 res/layout/quickspace_alternate_double.xml create mode 100644 res/layout/quickspace_doubleline.xml create mode 100644 res/layout/reserved_container_alternate_workspace.xml create mode 100644 res/layout/reserved_container_workspace.xml create mode 100644 res/values/derp_styles.xml create mode 100644 src/com/android/launcher3/quickspace/QuickEventsController.java create mode 100644 src/com/android/launcher3/quickspace/QuickSpaceView.java create mode 100644 src/com/android/launcher3/quickspace/QuickspaceController.java create mode 100644 src/com/android/launcher3/quickspace/receivers/QuickSpaceActionReceiver.java create mode 100644 src/com/android/launcher3/quickspace/views/DateTextView.java create mode 100644 src/com/android/launcher3/quickspace/views/DoubleShadowTextView.java diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml index db9c232673b..08dbf7be85d 100644 --- a/AndroidManifest-common.xml +++ b/AndroidManifest-common.xml @@ -64,6 +64,12 @@ + + + + + + + \ No newline at end of file diff --git a/res/drawable/ic_music_note_24dp.xml b/res/drawable/ic_music_note_24dp.xml new file mode 100644 index 00000000000..323633f8327 --- /dev/null +++ b/res/drawable/ic_music_note_24dp.xml @@ -0,0 +1,10 @@ + + + + diff --git a/res/drawable/ic_quickspace_derp.xml b/res/drawable/ic_quickspace_derp.xml new file mode 100644 index 00000000000..83bd670054b --- /dev/null +++ b/res/drawable/ic_quickspace_derp.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/res/drawable/ic_quickspace_evening.xml b/res/drawable/ic_quickspace_evening.xml new file mode 100644 index 00000000000..2192cf4d329 --- /dev/null +++ b/res/drawable/ic_quickspace_evening.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/res/drawable/ic_quickspace_midnight.xml b/res/drawable/ic_quickspace_midnight.xml new file mode 100644 index 00000000000..5b83510320e --- /dev/null +++ b/res/drawable/ic_quickspace_midnight.xml @@ -0,0 +1,7 @@ + + + diff --git a/res/drawable/ic_quickspace_morning.xml b/res/drawable/ic_quickspace_morning.xml new file mode 100644 index 00000000000..b74fc674873 --- /dev/null +++ b/res/drawable/ic_quickspace_morning.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/res/layout/quickspace_alternate_double.xml b/res/layout/quickspace_alternate_double.xml new file mode 100644 index 00000000000..8ec007f0643 --- /dev/null +++ b/res/layout/quickspace_alternate_double.xml @@ -0,0 +1,209 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/layout/quickspace_doubleline.xml b/res/layout/quickspace_doubleline.xml new file mode 100644 index 00000000000..3eb9aec7886 --- /dev/null +++ b/res/layout/quickspace_doubleline.xml @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/layout/reserved_container_alternate_workspace.xml b/res/layout/reserved_container_alternate_workspace.xml new file mode 100644 index 00000000000..d67157f18be --- /dev/null +++ b/res/layout/reserved_container_alternate_workspace.xml @@ -0,0 +1,34 @@ + + + + + + + + diff --git a/res/layout/reserved_container_workspace.xml b/res/layout/reserved_container_workspace.xml new file mode 100644 index 00000000000..76efb132480 --- /dev/null +++ b/res/layout/reserved_container_workspace.xml @@ -0,0 +1,35 @@ + + + + + + + + diff --git a/res/values/derp_config.xml b/res/values/derp_config.xml index 7a30e19cab3..596c83a5055 100644 --- a/res/values/derp_config.xml +++ b/res/values/derp_config.xml @@ -32,4 +32,7 @@ false + + + diff --git a/res/values/derp_dimens.xml b/res/values/derp_dimens.xml index ccc2faa22c4..62b97566d3b 100644 --- a/res/values/derp_dimens.xml +++ b/res/values/derp_dimens.xml @@ -12,4 +12,10 @@ 96dp 15dp 12dp + + + 20sp + 16sp + 18sp + 14sp diff --git a/res/values/derp_strings.xml b/res/values/derp_strings.xml index 3f0af120ff1..49a08eeb690 100644 --- a/res/values/derp_strings.xml +++ b/res/values/derp_strings.xml @@ -27,6 +27,7 @@ Other options General Interface + Quickspace Search bar Quick actions @@ -192,4 +193,213 @@ Force monochrome icons Force monochrome icons for apps that don\'t support them natively (requires re-toggling of themed icons) + + + At A Glance + Show at the top of your home screen + EEE, MMM d + EEEE, MMMM d + + + Welcome to DerpFest! + DerpFest time! + + Thank you for choosing us + Loving us? Send us a beer + Best Rom Ever. + Say hi to us on Telegram + Tap here to begin + We love you 3000 + + + + Good morning. + Good evening. + Good afternoon. + Good night. + Good day. + Today is + It\'s + + + Unknown Artist + Now playing + By + + + Now playing + Show the song you\'re playing + + + Extended style + Switch to extended style + + + Random messages + Make your companion more lively with random messages + + + Good morning! + Good morning, time to rock! + What a beautiful day! + Have a nice day! + What about a small 5 minutes nap? + Let\'s get this bread. + Mornings are a fresh canvas for your daily masterpiece. + Embrace the sunrise of opportunity each morning. + In the early light, find the power to illuminate your path. + Your day begins with endless possibilities. + Every sunrise is a reminder that you can start anew. + Awake with purpose, conquer the day ahead. + Your thoughts can be the foundation of great achievements. + The world awakens, and so does your potential. + The first chapter in your daily adventure. + Let your morning routine be the launchpad for success. + Sunrise or not, your potential is always on the rise. + It\'s time for fresh ideas and bold actions. + The early bird catches the worm, but you can catch your dreams. + Find the courage to chase your aspirations. + Rise and shine, for greatness awaits. + The best time to start is now. + + + Chase your dreams, not your fears. + In every moment, a new opportunity appears. + Embrace the journey, not just the destination. + Today is a gift, that\'s why it\'s called the present. + Let your smile change the world. + Life is a story, make each chapter count. + Find joy in every moments. + The best is yet to come, keep it up. + Your chance to turn \'what if\' into \'how about that\' + Seize the day, starting right now. + Happiness is a choice you can make any time. + Believe in yourself, even on a sleepy afternoon. + Let your actions speak louder than the clock. + Your life is yours, not your parents nor your friends. + Dream big, work hard, and never give up. + You are stronger than you think. + Every failure means a step closer to your success. + Your potential is endless, unlock it. + + + Embrace the present moment, no matter the hour. + In every dusk, find a new dawn of opportunity. + Life is a journey, enjoy the scenery along the way. + Your attitude shapes your reality. + Your story is still being written, even as the sun sets. + Capture the beauty in the ordinary moments. + It\'s time to reflect and reset. + Choose joy, no matter the time on the clock. + Opportunities don\'t clock out in the evening. + Be the reason someone smiles. + Your potential knows no bounds. + Moments of magic can happen at any hour. + Your life is what you make of it, make it extraordinary. + Stay curious, stay grateful. + Be the change you wish to see in the world. + Believe in yourself, you are capable of amazing things. + The only limit is the one you set for yourself. + Success begins with a single step. + + + Seize the night, for it holds its own mysteries. + In the quiet of the this evening, find serenity. + Life\'s greatest adventures can start in the darkness. + Your journey continues even after the sun has set. + Let the night be your canvas, paint it with dreams. + In the stillness of this evening, find your inner peace. + Stars shine brightest in the darkest hours. + Dream big, even in the late hours of the day. + Your life is a story waiting to be written. + It\'s time for reflection and renewal. + Late night thoughts can lead to early morning revelations. + Find joy in the stillness of this evening. + The night sky is a vast canvas of dreams. + Your potential knows no bedtime, pursue your passions. + Stay hopeful, even in the darkest hours. + In the midst of chaos, find your inner calm. + Stay positive, work hard, make it happen. + + + Nights are the quiet whispers of opportunity. + In the stillness of the night, find your inner strength. + Embrace the darkness, for it holds the keys to your dreams. + The world sleeps, but your potential is wide awake. + The night may be late, but your ambitions are timeless. + Stay curious, stay awake, and let nights guide you. + Find the courage to chase your dreams. + Great things never come from comfort zones. + You have the power to create your own destiny. + Happiness is a choice, choose it every day. + Life is what you make it, so make it count. + Stay focused, stay determined, stay unstoppable. + You are the author of your own story. + Strive for progress, not perfection. + Every day is a new beginning, make it a great one. + Inspire others by being your authentic self. + Your attitude determines your direction. + + + Ignorance is Bliss + Is it time to flash another update already? + Make peace, not war + Oh hey, what\'s up? + Focus on your tasks + How many screenshots do you take? + Open goodness with DerpFest + Spread love, not havoc + We didn\'t start the fire! + Time for some good music + \u003C\u003C\u003C\u003C\u003C\u003C\u003C HEAD + You need DerpFest Premium to see this + Remember the Lineage of the Unicorn + Enjoy Xtended battery life + Starting from the ground zero + We love you 3000 + Delicious even without Sushi + Do something nice today + This is best Pixel Experience, isn\'t it? + No illusions, welcome to reality! + Thank you for your support + No festival for Derps - only perfection! + One of the buildbot\'s best picks + Sanity for your Paranoia + Try Ice Cold desserts + What a lovely experience, isn\'t it? + DerpFest is a myth, right? + You are what you flash, don\'t be Potato + What\'s on your mind? + Expecto Patronum + Wubba Lubba Dub Dub + Winner Winner ....? + rm -rf \/ + Pringles aren\'t actually potato chips.. + Remember to check device\'s battery level! + Check your email/messages. + Check your to-do list if you have one. + You can disable quickspace via home settings. + + + + Weather update + Display current weather update + Requires weather service to be enabled + Cloudy + Rainy + Sunny + Stormy + Snowy + Windy + Misty + Current location + Display current weather location + Current condition + Display current weather condition summary + + Unable to find calendar or clock activity + + + Weather settings + Setup icon pack and weather service diff --git a/res/values/derp_styles.xml b/res/values/derp_styles.xml new file mode 100644 index 00000000000..5f9725bdbec --- /dev/null +++ b/res/values/derp_styles.xml @@ -0,0 +1,16 @@ + + + + + + + + + diff --git a/res/xml/launcher_home_screen_preferences.xml b/res/xml/launcher_home_screen_preferences.xml index dc4ab92254e..a9e2aa22334 100644 --- a/res/xml/launcher_home_screen_preferences.xml +++ b/res/xml/launcher_home_screen_preferences.xml @@ -140,6 +140,82 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java index c7cdfa8c693..9316b1473f6 100644 --- a/src/com/android/launcher3/AutoInstallsLayout.java +++ b/src/com/android/launcher3/AutoInstallsLayout.java @@ -50,7 +50,6 @@ import com.android.launcher3.model.data.LauncherAppWidgetInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.pm.UserCache; -import com.android.launcher3.qsb.QsbContainerView; import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.uioverrides.ApiWrapper; import com.android.launcher3.util.IntArray; @@ -128,7 +127,6 @@ public static AutoInstallsLayout get(Context context, LauncherWidgetHolder appWi private static final String TAG_AUTO_INSTALL = "autoinstall"; private static final String TAG_FOLDER = "folder"; private static final String TAG_APPWIDGET = "appwidget"; - protected static final String TAG_SEARCH_WIDGET = "searchwidget"; private static final String TAG_SHORTCUT = "shortcut"; private static final String TAG_EXTRA = "extra"; @@ -342,7 +340,6 @@ protected ArrayMap getLayoutElementsMap() { parsers.put(TAG_AUTO_INSTALL, new AutoInstallParser()); parsers.put(TAG_FOLDER, new FolderParser()); parsers.put(TAG_APPWIDGET, new PendingWidgetParser()); - parsers.put(TAG_SEARCH_WIDGET, new SearchWidgetParser()); parsers.put(TAG_SHORTCUT, new ShortcutParser()); return parsers; } @@ -534,24 +531,6 @@ protected int verifyAndInsert(ComponentName cn, Bundle extras) { } } - protected class SearchWidgetParser extends PendingWidgetParser { - @Override - @Nullable - @WorkerThread - public ComponentName getComponentName(XmlPullParser parser) { - return QsbContainerView.getSearchComponentName(mContext); - } - - @Override - protected int verifyAndInsert(ComponentName cn, Bundle extras) { - mValues.put(Favorites.OPTIONS, LauncherAppWidgetInfo.OPTION_SEARCH_WIDGET); - int flags = mValues.getAsInteger(Favorites.RESTORED) - | WorkspaceItemInfo.FLAG_RESTORE_STARTED; - mValues.put(Favorites.RESTORED, flags); - return super.verifyAndInsert(cn, extras); - } - } - protected class FolderParser implements TagParser { private final ArrayMap mFolderElements; diff --git a/src/com/android/launcher3/DefaultLayoutParser.java b/src/com/android/launcher3/DefaultLayoutParser.java index c748693f9bd..1949c9a2c3b 100644 --- a/src/com/android/launcher3/DefaultLayoutParser.java +++ b/src/com/android/launcher3/DefaultLayoutParser.java @@ -70,7 +70,6 @@ protected ArrayMap getLayoutElementsMap() { ArrayMap parsers = new ArrayMap<>(); parsers.put(TAG_FAVORITE, new AppShortcutWithUriParser()); parsers.put(TAG_APPWIDGET, new AppWidgetParser()); - parsers.put(TAG_SEARCH_WIDGET, new SearchWidgetParser()); parsers.put(TAG_SHORTCUT, new ShortcutParser()); parsers.put(TAG_RESOLVE, new ResolveParser()); parsers.put(TAG_FOLDER, new MyFolderParser()); diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 7aa8c4a9b2a..8d3bffbb4ad 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -204,7 +204,7 @@ import com.android.launcher3.popup.ArrowPopup; import com.android.launcher3.popup.PopupDataProvider; import com.android.launcher3.popup.SystemShortcut; -import com.android.launcher3.qsb.QsbContainerView; +import com.android.launcher3.quickspace.QuickSpaceView; import com.android.launcher3.statemanager.StateManager; import com.android.launcher3.statemanager.StateManager.StateHandler; import com.android.launcher3.statemanager.StatefulActivity; @@ -410,6 +410,9 @@ public class Launcher extends StatefulActivity private final SettingsCache.OnChangeListener mNaturalScrollingChangedListener = enabled -> mIsNaturalScrollingEnabled = enabled; + // QuickSpace + private QuickSpaceView mQuickSpace; + public static Launcher getLauncher(Context context) { return fromContext(context); } @@ -1050,6 +1053,9 @@ protected void onStop() { } else { mOverlayManager.onActivityStopped(); } + if (mQuickSpace != null) { + mQuickSpace.onPause(); + } hideKeyboard(); logStopAndResume(false /* isResume */); mAppWidgetHolder.setActivityStarted(false); @@ -1238,6 +1244,10 @@ protected void onResume() { TraceHelper.INSTANCE.beginSection(ON_RESUME_EVT); super.onResume(); + if (mQuickSpace != null) { + mQuickSpace.onResume(); + } + if (mDeferOverlayCallbacks) { scheduleDeferredCheck(); } else { @@ -1263,6 +1273,9 @@ protected void onPause() { if (!mDeferOverlayCallbacks) { mOverlayManager.onActivityPaused(); } + if (mQuickSpace != null) { + mQuickSpace.onPause(); + } mAppWidgetHolder.setActivityResumed(false); } @@ -1346,6 +1359,9 @@ protected void setupViews() { // Setup Scrim mScrimView = findViewById(R.id.scrim_view); + // QuickSpace + mQuickSpace = findViewById(R.id.reserved_container_workspace); + // Setup the drag controller (drop targets have to be added in reverse order in priority) mDropTargetBar.setup(mDragController); mAllAppsController.setupViews(mScrimView, mAppsView); @@ -1746,6 +1762,10 @@ public void onDestroy() { // changes while launcher is still loading. getRootView().getViewTreeObserver().removeOnPreDrawListener(mOnInitialBindListener); mOverlayManager.onActivityDestroyed(); + + if (mQuickSpace != null) { + mQuickSpace.onPause(); + } } public LauncherAccessibilityDelegate getAccessibilityDelegate() { @@ -2315,14 +2335,6 @@ public void bindAppWidget(LauncherAppWidgetInfo item) { } private View inflateAppWidget(LauncherAppWidgetInfo item) { - if (item.hasOptionFlag(LauncherAppWidgetInfo.OPTION_SEARCH_WIDGET)) { - item.providerName = QsbContainerView.getSearchComponentName(this); - if (item.providerName == null) { - getModelWriter().deleteItemFromDatabase(item, - "search widget removed because search component cannot be found"); - return null; - } - } final AppWidgetHostView view; if (mIsSafeModeEnabled) { view = new PendingAppWidgetHostView(this, item, mIconCache, true); diff --git a/src/com/android/launcher3/ModelCallbacks.kt b/src/com/android/launcher3/ModelCallbacks.kt index 51729992d45..ac6552df358 100644 --- a/src/com/android/launcher3/ModelCallbacks.kt +++ b/src/com/android/launcher3/ModelCallbacks.kt @@ -35,8 +35,7 @@ class ModelCallbacks(private var launcher: Launcher) : BgDataModel.Callbacks { var synchronouslyBoundPages = LIntSet() var pagesToBindSynchronously = LIntSet() - private var isFirstPagePinnedItemEnabled = - (BuildConfig.QSB_ON_FIRST_SCREEN && !FeatureFlags.ENABLE_SMARTSPACE_REMOVAL.get()) + private var isFirstPagePinnedItemEnabled = FeatureFlags.USE_QUICKSPACE_VIEW var stringCache: StringCache? = null @@ -309,15 +308,14 @@ class ModelCallbacks(private var launcher: Launcher) : BgDataModel.Callbacks { ) val firstScreenPosition = 0 if ( - (FeatureFlags.QSB_ON_FIRST_SCREEN && - isFirstPagePinnedItemEnabled && + (isFirstPagePinnedItemEnabled && !shouldShowFirstPageWidget()) && orderedScreenIds.indexOf(FIRST_SCREEN_ID) != firstScreenPosition ) { orderedScreenIds.removeValue(FIRST_SCREEN_ID) orderedScreenIds.add(firstScreenPosition, FIRST_SCREEN_ID) } else if ( - (!FeatureFlags.QSB_ON_FIRST_SCREEN && !isFirstPagePinnedItemEnabled || + (!isFirstPagePinnedItemEnabled || shouldShowFirstPageWidget()) && orderedScreenIds.isEmpty ) { // If there are no screens, we need to have an empty screen @@ -374,8 +372,7 @@ class ModelCallbacks(private var launcher: Launcher) : BgDataModel.Callbacks { } orderedScreenIds .filterNot { screenId -> - FeatureFlags.QSB_ON_FIRST_SCREEN && - isFirstPagePinnedItemEnabled && + isFirstPagePinnedItemEnabled && !FeatureFlags.shouldShowFirstPageWidget() && screenId == WorkspaceLayoutManager.FIRST_SCREEN_ID } diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index bbbe984c724..cf6ff91e720 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -58,6 +58,8 @@ import android.graphics.drawable.InsetDrawable; import android.hardware.biometrics.BiometricManager.Authenticators; import android.hardware.biometrics.BiometricPrompt; +import android.icu.text.DateFormat; +import android.icu.text.DisplayContext; import android.os.Build; import android.os.Build.VERSION_CODES; import android.os.CancellationSignal; @@ -69,6 +71,7 @@ import android.text.Spannable; import android.text.SpannableString; import android.text.TextUtils; +import android.text.format.DateUtils; import android.text.style.TtsSpan; import android.util.DisplayMetrics; import android.util.Log; @@ -197,6 +200,13 @@ public final class Utilities { public static final String KEY_LENS = "pref_recents_lens"; public static final String KEY_SHORT_PARALLAX = "pref_short_parallax"; public static final String KEY_SINGLE_PAGE_CENTER = "pref_single_page_center"; + public static final String DESKTOP_SHOW_QUICKSPACE = "pref_show_quickspace"; + public static final String KEY_SHOW_ALT_QUICKSPACE = "pref_show_alt_quickspace"; + public static final String KEY_SHOW_QUICKSPACE_PSONALITY = "pref_quickspace_psonality"; + public static final String KEY_SHOW_QUICKSPACE_NOWPLAYING = "pref_quickspace_np"; + public static final String KEY_SHOW_QUICKSPACE_WEATHER = "pref_quickspace_weather"; + public static final String KEY_SHOW_QUICKSPACE_WEATHER_CITY = "pref_quickspace_weather_city"; + public static final String KEY_SHOW_QUICKSPACE_WEATHER_TEXT = "pref_quickspace_weather_text"; /** * Returns true if theme is dark. @@ -879,6 +889,19 @@ public static void translateOverlappingView( } } + public static String formatDateTime(Context context) { + String styleText; + DateFormat dateFormat; + if (useAlternativeQuickspaceUI(context)) { + styleText = context.getString(R.string.quickspace_date_format_minimalistic); + } else { + styleText = context.getString(R.string.quickspace_date_format); + } + dateFormat = DateFormat.getInstanceForSkeleton(styleText, Locale.getDefault()); + dateFormat.setContext(DisplayContext.CAPITALIZATION_FOR_STANDALONE); + return dateFormat.format(System.currentTimeMillis()); + } + public static boolean isWorkspaceEditAllowed(Context context) { SharedPreferences prefs = LauncherPrefs.getPrefs(context.getApplicationContext()); return !prefs.getBoolean(InvariantDeviceProfile.KEY_WORKSPACE_LOCK, false); @@ -1019,4 +1042,39 @@ public static boolean isSinglePageCentered(Context context) { public static boolean isDebugDevice() { return !Build.IS_USER; } + + public static boolean showQuickspace(Context context) { + SharedPreferences prefs = LauncherPrefs.getPrefs(context.getApplicationContext()); + return prefs.getBoolean(DESKTOP_SHOW_QUICKSPACE, true); + } + + public static boolean useAlternativeQuickspaceUI(Context context) { + SharedPreferences prefs = LauncherPrefs.getPrefs(context.getApplicationContext()); + return prefs.getBoolean(KEY_SHOW_ALT_QUICKSPACE, false); + } + + public static boolean isQuickspacePersonalityEnabled(Context context) { + SharedPreferences prefs = LauncherPrefs.getPrefs(context.getApplicationContext()); + return prefs.getBoolean(KEY_SHOW_QUICKSPACE_PSONALITY, true); + } + + public static boolean isQuickspaceNowPlaying(Context context) { + SharedPreferences prefs = LauncherPrefs.getPrefs(context.getApplicationContext()); + return prefs.getBoolean(KEY_SHOW_QUICKSPACE_NOWPLAYING, true); + } + + public static boolean isQuickspaceWeather(Context context) { + SharedPreferences prefs = LauncherPrefs.getPrefs(context.getApplicationContext()); + return prefs.getBoolean(KEY_SHOW_QUICKSPACE_WEATHER, true); + } + + public static boolean QuickSpaceShowCity(Context context) { + SharedPreferences prefs = LauncherPrefs.getPrefs(context.getApplicationContext()); + return prefs.getBoolean(KEY_SHOW_QUICKSPACE_WEATHER_CITY, false); + } + + public static boolean QuickSpaceShowWeatherText(Context context) { + SharedPreferences prefs = LauncherPrefs.getPrefs(context.getApplicationContext()); + return prefs.getBoolean(KEY_SHOW_QUICKSPACE_WEATHER_TEXT, true); + } } diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 3fbc584f084..2a08fd2b315 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -600,9 +600,10 @@ public void onViewAdded(View child) { * Initializes and binds the first page */ public void bindAndInitFirstWorkspaceScreen() { - if ((!FeatureFlags.QSB_ON_FIRST_SCREEN + if ((!Utilities.showQuickspace(getContext()) || !mLauncher.getIsFirstPagePinnedItemEnabled()) || shouldShowFirstPageWidget()) { + insertNewWorkspaceScreen(Workspace.FIRST_SCREEN_ID, getChildCount()); mFirstPagePinnedItem = null; return; } @@ -614,14 +615,14 @@ public void bindAndInitFirstWorkspaceScreen() { // As workspace does not touch the edges, we do not need a full // width first page pinned item. mFirstPagePinnedItem = LayoutInflater.from(getContext()) - .inflate(R.layout.search_container_workspace, firstPage, false); + .inflate(R.layout.reserved_container_workspace, firstPage, false); } int cellHSpan = mLauncher.getDeviceProfile().inv.numSearchContainerColumns; CellLayoutLayoutParams lp = new CellLayoutLayoutParams(0, 0, cellHSpan, 1); lp.canReorder = false; if (!firstPage.addViewToCellLayout( - mFirstPagePinnedItem, 0, R.id.search_container_workspace, lp, true)) { + mFirstPagePinnedItem, 0, R.id.reserved_container_workspace, lp, true)) { Log.e(TAG, "Failed to add to item at (0, 0) to CellLayout"); mFirstPagePinnedItem = null; } @@ -812,7 +813,7 @@ private void convertFinalScreenToEmptyScreenIfNecessary() { // We don't want to remove the first screen even if it's empty because that's where // first page pinned item would go if it gets turned back on. - if (ENABLE_SMARTSPACE_REMOVAL.get() && screenId == FIRST_SCREEN_ID) { + if (FeatureFlags.USE_QUICKSPACE_VIEW && screenId == FIRST_SCREEN_ID) { continue; } @@ -1029,7 +1030,7 @@ public void stripEmptyScreens() { int id = mWorkspaceScreens.keyAt(i); CellLayout cl = mWorkspaceScreens.valueAt(i); // FIRST_SCREEN_ID can never be removed. - if (((!FeatureFlags.QSB_ON_FIRST_SCREEN + if (((!FeatureFlags.USE_QUICKSPACE_VIEW || shouldShowFirstPageWidget()) || id > FIRST_SCREEN_ID) && cl.getShortcutsAndWidgets().getChildCount() == 0) { diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java index f807bdf7b19..a9a21be0f8f 100644 --- a/src/com/android/launcher3/config/FeatureFlags.java +++ b/src/com/android/launcher3/config/FeatureFlags.java @@ -62,7 +62,7 @@ private FeatureFlags() { } * @deprecated Use {@link BuildConfig#QSB_ON_FIRST_SCREEN} directly */ @Deprecated - public static final boolean QSB_ON_FIRST_SCREEN = BuildConfig.QSB_ON_FIRST_SCREEN; + public static final boolean USE_QUICKSPACE_VIEW = true; /** * Feature flag to handle define config changes dynamically instead of killing the process. diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java index 33304489196..126c04c91ce 100644 --- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java +++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java @@ -527,14 +527,14 @@ private void populate(BgDataModel dataModel, } // Add first page QSB - if (FeatureFlags.QSB_ON_FIRST_SCREEN && dataModel.isFirstPagePinnedItemEnabled + if (FeatureFlags.USE_QUICKSPACE_VIEW && dataModel.isFirstPagePinnedItemEnabled && !shouldShowFirstPageWidget()) { CellLayout firstScreen = mWorkspaceScreens.get(FIRST_SCREEN_ID); View qsb = mHomeElementInflater.inflate(R.layout.qsb_preview, firstScreen, false); CellLayoutLayoutParams lp = new CellLayoutLayoutParams( 0, 0, firstScreen.getCountX(), 1); lp.canReorder = false; - firstScreen.addViewToCellLayout(qsb, 0, R.id.search_container_workspace, lp, true); + firstScreen.addViewToCellLayout(qsb, 0, R.id.reserved_container_workspace, lp, true); } measureView(mRootView, mDp.widthPx, mDp.heightPx); diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java index 7f0f683091e..a30d30da763 100644 --- a/src/com/android/launcher3/model/BgDataModel.java +++ b/src/com/android/launcher3/model/BgDataModel.java @@ -17,7 +17,6 @@ import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY; -import static com.android.launcher3.BuildConfig.QSB_ON_FIRST_SCREEN; import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL; import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget; import static com.android.launcher3.model.WidgetsModel.GO_DISABLE_WIDGETS; @@ -132,7 +131,7 @@ public class BgDataModel { * Load id for which the callbacks were successfully bound */ public int lastLoadId = -1; - public boolean isFirstPagePinnedItemEnabled = QSB_ON_FIRST_SCREEN + public boolean isFirstPagePinnedItemEnabled = FeatureFlags.USE_QUICKSPACE_VIEW && !ENABLE_SMARTSPACE_REMOVAL.get(); /** @@ -157,7 +156,7 @@ public synchronized IntArray collectWorkspaceScreens() { screenSet.add(item.screenId); } } - if ((FeatureFlags.QSB_ON_FIRST_SCREEN + if ((FeatureFlags.USE_QUICKSPACE_VIEW && !shouldShowFirstPageWidget()) || screenSet.isEmpty()) { screenSet.add(Workspace.FIRST_SCREEN_ID); diff --git a/src/com/android/launcher3/model/DatabaseHelper.java b/src/com/android/launcher3/model/DatabaseHelper.java index 13605101e75..de9eb5039b0 100644 --- a/src/com/android/launcher3/model/DatabaseHelper.java +++ b/src/com/android/launcher3/model/DatabaseHelper.java @@ -258,7 +258,7 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { Favorites.SCREEN, IntArray.wrap(-777, -778)), null); } case 30: { - if (FeatureFlags.QSB_ON_FIRST_SCREEN + if (Utilities.showQuickspace(mContext) && !shouldShowFirstPageWidget()) { // Clean up first row in screen 0 as it might contain junk data. Log.d(TAG, "Cleaning up first row"); diff --git a/src/com/android/launcher3/model/GridSizeMigrationUtil.java b/src/com/android/launcher3/model/GridSizeMigrationUtil.java index efd55745196..086c7664be2 100644 --- a/src/com/android/launcher3/model/GridSizeMigrationUtil.java +++ b/src/com/android/launcher3/model/GridSizeMigrationUtil.java @@ -332,7 +332,7 @@ private static void solveGridPlacement(@NonNull final DatabaseHelper helper, final GridOccupancy occupied = new GridOccupancy(trgX, trgY); final Point trg = new Point(trgX, trgY); final Point next = new Point(0, screenId == 0 - && (FeatureFlags.QSB_ON_FIRST_SCREEN + && (Utilities.showQuickspace(destReader.mContext) && (!ENABLE_SMARTSPACE_REMOVAL.get() || LauncherPrefs.getPrefs(destReader.mContext) .getBoolean(SMARTSPACE_ON_HOME_SCREEN, true)) && !shouldShowFirstPageWidget()) diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java index 43700435694..5ffdb137385 100644 --- a/src/com/android/launcher3/model/LoaderCursor.java +++ b/src/com/android/launcher3/model/LoaderCursor.java @@ -529,7 +529,7 @@ protected boolean checkItemPlacement(ItemInfo item, boolean isFirstPagePinnedIte if (!mOccupied.containsKey(item.screenId)) { GridOccupancy screen = new GridOccupancy(countX + 1, countY + 1); - if (item.screenId == Workspace.FIRST_SCREEN_ID && (FeatureFlags.QSB_ON_FIRST_SCREEN + if (item.screenId == Workspace.FIRST_SCREEN_ID && (Utilities.showQuickspace(mContext) && !shouldShowFirstPageWidget() && isFirstPagePinnedItemEnabled)) { // Mark the first X columns (X is width of the search container) in the first row as // occupied (if the feature is enabled) in order to account for the search diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index 10ae171f9a3..5492bc40da0 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -383,9 +383,7 @@ protected void loadWorkspace( mModelDelegate.markActive(); logASplit("workspaceDelegateItems"); } - mBgDataModel.isFirstPagePinnedItemEnabled = FeatureFlags.QSB_ON_FIRST_SCREEN - && (!ENABLE_SMARTSPACE_REMOVAL.get() || LauncherPrefs.getPrefs( - mApp.getContext()).getBoolean(SMARTSPACE_ON_HOME_SCREEN, true)); + mBgDataModel.isFirstPagePinnedItemEnabled = FeatureFlags.USE_QUICKSPACE_VIEW; } private void loadWorkspaceImpl( @@ -770,15 +768,8 @@ private void processWorkspaceItem(LoaderCursor c, String savedProvider = c.getAppWidgetProvider(); final ComponentName component; - if ((c.getOptions() & LauncherAppWidgetInfo.OPTION_SEARCH_WIDGET) != 0) { - component = QsbContainerView.getSearchComponentName(mApp.getContext()); - if (component == null) { - c.markDeleted("Discarding SearchWidget without packagename "); - return; - } - } else { - component = ComponentName.unflattenFromString(savedProvider); - } + component = ComponentName.unflattenFromString(savedProvider); + final boolean isIdValid = !c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID); final boolean wasProviderReady = diff --git a/src/com/android/launcher3/model/WorkspaceItemSpaceFinder.java b/src/com/android/launcher3/model/WorkspaceItemSpaceFinder.java index 929f698236e..01536c6219c 100644 --- a/src/com/android/launcher3/model/WorkspaceItemSpaceFinder.java +++ b/src/com/android/launcher3/model/WorkspaceItemSpaceFinder.java @@ -23,6 +23,7 @@ import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherSettings; +import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.util.GridOccupancy; @@ -67,7 +68,7 @@ public int[] findSpaceForItem(LauncherAppState app, BgDataModel dataModel, int screenCount = workspaceScreens.size(); // First check the preferred screen. IntSet screensToExclude = new IntSet(); - if (FeatureFlags.QSB_ON_FIRST_SCREEN + if (Utilities.showQuickspace(app.getContext()) && !shouldShowFirstPageWidget()) { screensToExclude.add(FIRST_SCREEN_ID); } diff --git a/src/com/android/launcher3/quickspace/QuickEventsController.java b/src/com/android/launcher3/quickspace/QuickEventsController.java new file mode 100644 index 00000000000..0d9cee9a093 --- /dev/null +++ b/src/com/android/launcher3/quickspace/QuickEventsController.java @@ -0,0 +1,428 @@ +/* + * Copyright (C) 2018 CypherOS + * + * 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.quickspace; + +import android.app.PendingIntent; +import android.content.ActivityNotFoundException; +import android.content.ComponentName; +import android.content.Context; +import android.content.BroadcastReceiver; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.SharedPreferences; +import android.media.MediaMetadata; +import android.media.session.MediaController; +import android.media.session.MediaSession; +import android.media.session.MediaSessionManager; +import android.net.Uri; +import android.provider.AlarmClock; +import android.provider.Settings; +import android.text.TextUtils; +import android.widget.Toast; +import android.view.View; +import android.view.View.OnClickListener; + +import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherFiles; +import com.android.launcher3.R; +import com.android.launcher3.Utilities; + +import java.util.Calendar; +import java.util.Random; + +import java.util.List; + +public class QuickEventsController { + + private static final String SETTING_DEVICE_INTRO_COMPLETED = "device_introduction_completed"; + private Context mContext; + + private String mEventTitle; + private String mEventTitleSub; + private String mGreetings; + private String mClockExt; + private OnClickListener mEventTitleSubAction = null; + private int mEventSubIcon = 0; + + private boolean mIsQuickEvent = false; + private boolean mRunning = true; + private boolean mRegistered = false; + + // Device Intro + private boolean mIsFirstTimeDone = false; + private SharedPreferences mPreferences; + + // PSA + Personality + private String[] mPSAMorningStr; + private String[] mPSAEvenStr; + private String[] mPSAAfterNoonStr; + private String[] mPSAMidniteStr; + private String[] mPSARandomStr; + private String[] mPSAEarlyEvenStr; + private String[] mWelcomeStr; + private BroadcastReceiver mPSAListener = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + psonalityEvent(); + } + }; + + // NowPlaying + private boolean mEventNowPlaying = false; + private String mNowPlayingTitle; + private String mNowPlayingArtist; + private boolean mClientLost = true; + private boolean mPlayingActive = false; + + public QuickEventsController(Context context) { + mContext = context; + initQuickEvents(); + } + + public void initQuickEvents() { + mPreferences = mContext.getSharedPreferences(LauncherFiles.SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE); + mIsFirstTimeDone = mPreferences.getBoolean(SETTING_DEVICE_INTRO_COMPLETED, false); + registerPSAListener(); + updateQuickEvents(); + } + + private void registerPSAListener() { + if (mRegistered) return; + mRegistered = true; + IntentFilter psonalityIntent = new IntentFilter(); + psonalityIntent.addAction(Intent.ACTION_TIME_TICK); + psonalityIntent.addAction(Intent.ACTION_TIME_CHANGED); + psonalityIntent.addAction(Intent.ACTION_TIMEZONE_CHANGED); + mContext.registerReceiver(mPSAListener, psonalityIntent, Context.RECEIVER_NOT_EXPORTED); + } + + private void unregisterPSAListener() { + if (!mRegistered) return; + mRegistered = false; + mContext.unregisterReceiver(mPSAListener); + } + + public void updateQuickEvents() { + deviceIntroEvent(); + nowPlayingEvent(); + initNowPlayingEvent(); + psonalityEvent(); + } + + private void deviceIntroEvent() { + if (!mRunning) return; + + if (mIsFirstTimeDone) return; + + mIsQuickEvent = true; + + if (Utilities.useAlternativeQuickspaceUI(mContext)) { + mEventTitle = mContext.getResources().getString(R.string.quick_event_rom_intro_welcome_ext); + } else { + mEventTitle = mContext.getResources().getString(R.string.quick_event_rom_intro_welcome); + } + mWelcomeStr = mContext.getResources().getStringArray(R.array.welcome_message_variants); + mEventTitleSub = mWelcomeStr[getLuckyNumber(0,mWelcomeStr.length - 1)]; + mEventSubIcon = R.drawable.ic_quickspace_derp; + mGreetings = mContext.getResources().getString(R.string.quickspace_grt_general); + mClockExt = mContext.getResources().getString(R.string.quickspace_ext_two); + + mEventTitleSubAction = new OnClickListener() { + @Override + public void onClick(View view) { + mContext.getSharedPreferences(LauncherFiles.SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE) + .edit() + .putBoolean(SETTING_DEVICE_INTRO_COMPLETED, true) + .commit(); + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.addCategory(Intent.CATEGORY_HOME); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + try { + Launcher.getLauncher(mContext).startActivitySafely(view, intent, null); + } catch (ActivityNotFoundException ex) { + } + mIsQuickEvent = false; + } + }; + } + + public void nowPlayingEvent() { + if (mEventNowPlaying) { + boolean infoExpired = !mPlayingActive || mClientLost; + if (infoExpired) { + mIsQuickEvent = false; + mEventNowPlaying = false; + } + } + } + + public void initNowPlayingEvent() { + if (!mRunning) return; + + if (!mIsFirstTimeDone) return; + + if (!Utilities.isQuickspaceNowPlaying(mContext)) return; + + if (!mPlayingActive) return; + + if (mNowPlayingTitle == null) return; + + mEventTitle = mNowPlayingTitle; + mGreetings = mContext.getResources().getString(R.string.qe_now_playing_ext_one); + mClockExt = ""; + if (mNowPlayingArtist == null ) { + mEventTitleSub = mContext.getResources().getString(R.string.qe_now_playing_unknown_artist); + } else { + mEventTitleSub = mNowPlayingArtist; + } + mEventSubIcon = R.drawable.ic_music_note_24dp; + mIsQuickEvent = true; + mEventNowPlaying = true; + + mEventTitleSubAction = new View.OnClickListener() { + @Override + public void onClick(View view) { + if (mPlayingActive) { + MediaSessionManager mediaSessionManager = (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE); + List sessions = mediaSessionManager.getActiveSessions(null); + + if (sessions != null && !sessions.isEmpty()) { + MediaController mediaController = sessions.get(0); + MediaSession.Token token = mediaController.getSessionToken(); + PendingIntent sessionActivity = mediaController.getSessionActivity(); + + if (sessionActivity != null) { + Intent intent = sessionActivity.getIntent(); + + if (intent != null) { + ComponentName componentName = intent.getComponent(); + if (componentName != null) { + String packageName = componentName.getPackageName(); + if (packageName != null) { + Intent launchIntent = mContext.getPackageManager().getLaunchIntentForPackage(packageName); + + if (launchIntent != null) { + launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + try { + // try if package name launch intent works + mContext.startActivity(launchIntent); + return; // Exit the method after starting the activity + } catch (Exception e) {} + } + } + } + + try { + // try session activity + mContext.startActivity(intent); + return; // Exit the method after starting the activity + } catch (Exception e) {} + } + } + + // last resort: Work required for local media actions + Intent npIntent = new Intent(Intent.ACTION_MAIN); + npIntent.addCategory(Intent.CATEGORY_APP_MUSIC); + npIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + try { + Launcher.getLauncher(mContext).startActivitySafely(view, npIntent, null); + } catch (ActivityNotFoundException ex) {} + } + } + } + }; + } + + public void psonalityEvent() { + if (!mIsFirstTimeDone || mEventNowPlaying) return; + mEventSubIcon = 0; + + mEventTitle = Utilities.formatDateTime(mContext); + mPSAMorningStr = mContext.getResources().getStringArray(R.array.quickspace_psa_morning); + mPSAEvenStr = mContext.getResources().getStringArray(R.array.quickspace_psa_evening); + mPSAEarlyEvenStr = mContext.getResources().getStringArray(R.array.quickspace_psa_early_evening); + mPSAMidniteStr = mContext.getResources().getStringArray(R.array.quickspace_psa_midnight); + mPSAAfterNoonStr = mContext.getResources().getStringArray(R.array.quickspace_psa_noon); + mPSARandomStr = mContext.getResources().getStringArray(R.array.quickspace_psa_random); + int psaLength; + + mEventTitleSubAction = new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent calendarIntent = new Intent(Intent.ACTION_MAIN); + calendarIntent.addCategory(Intent.CATEGORY_APP_CALENDAR); + + Intent clockIntent = new Intent(AlarmClock.ACTION_SHOW_ALARMS); + + PackageManager packageManager = mContext.getPackageManager(); + List calendarApps = packageManager.queryIntentActivities(calendarIntent, PackageManager.MATCH_DEFAULT_ONLY); + List clockApps = packageManager.queryIntentActivities(clockIntent, PackageManager.MATCH_DEFAULT_ONLY); + + if (!calendarApps.isEmpty()) { + calendarIntent.setPackage(calendarApps.get(0).activityInfo.packageName); + try { + mContext.startActivity(calendarIntent); + } catch (ActivityNotFoundException e) { + } + } else if (!clockApps.isEmpty()) { + clockIntent.setPackage(clockApps.get(0).activityInfo.packageName); + try { + mContext.startActivity(clockIntent); + } catch (ActivityNotFoundException e) { + } + } else { + Toast.makeText(mContext, R.string.intent_no_app_clock_found, Toast.LENGTH_SHORT).show(); + } + } + }; + + int hourOfDay = Calendar.getInstance().get(Calendar.HOUR_OF_DAY); + + if (hourOfDay >= 5 && hourOfDay <= 9) { + mGreetings = mContext.getResources().getString(R.string.quickspace_grt_morning); + mClockExt = mContext.getResources().getString(R.string.quickspace_ext_one); + } else if (hourOfDay >= 12 && hourOfDay <= 15) { + mGreetings = mContext.getResources().getString(R.string.quickspace_grt_afternoon); + mClockExt = mContext.getResources().getString(R.string.quickspace_ext_two); + } else if (hourOfDay >= 16 && hourOfDay <= 20) { + mGreetings = mContext.getResources().getString(R.string.quickspace_grt_evening); + mClockExt = mContext.getResources().getString(R.string.quickspace_ext_two); + } else if (hourOfDay >= 21 && hourOfDay <= 23) { + mGreetings = mContext.getResources().getString(R.string.quickspace_grt_night); + mClockExt = mContext.getResources().getString(R.string.quickspace_ext_two); + } else if (hourOfDay >= 0 && hourOfDay <= 3) { + mGreetings = mContext.getResources().getString(R.string.quickspace_grt_night); + mClockExt = mContext.getResources().getString(R.string.quickspace_ext_two); + } else { + mGreetings = mContext.getResources().getString(R.string.quickspace_grt_general); + mClockExt = mContext.getResources().getString(R.string.quickspace_ext_two); + } + + if (Utilities.isQuickspacePersonalityEnabled(mContext)) { + if (getLuckyNumber(13) == 7) { + psaLength = mPSARandomStr.length - 1; + mEventTitleSub = mPSARandomStr[getLuckyNumber(0, psaLength)]; + mEventSubIcon = R.drawable.ic_quickspace_derp; + mIsQuickEvent = true; + } else { + switch (hourOfDay) { + case 5: case 6: case 7: case 8: case 9: + psaLength = mPSAMorningStr.length - 1; + mEventTitleSub = mPSAMorningStr[getLuckyNumber(0, psaLength)]; + mIsQuickEvent = true; + break; + + case 19: case 20: case 21: + psaLength = mPSAEvenStr.length - 1; + mEventTitleSub = mPSAEvenStr[getLuckyNumber(0, psaLength)]; + mIsQuickEvent = true; + break; + + case 16: case 17: case 18: + psaLength = mPSAEarlyEvenStr.length - 1; + mEventTitleSub = mPSAEarlyEvenStr[getLuckyNumber(0, psaLength)]; + mIsQuickEvent = true; + break; + + case 12: case 13: case 14: case 15: + psaLength = mPSAAfterNoonStr.length - 1; + mEventTitleSub = mPSAAfterNoonStr[getLuckyNumber(0, psaLength)]; + mIsQuickEvent = true; + break; + + case 0: case 1: case 2: case 3: + psaLength = mPSAMidniteStr.length - 1; + mEventTitleSub = mPSAMidniteStr[getLuckyNumber(0, psaLength)]; + mIsQuickEvent = true; + break; + + default: + mEventTitleSub = null; + mIsQuickEvent = false; + break; + } + } + } else { + mEventTitleSub = null; + mIsQuickEvent = false; + } + } + + public boolean isQuickEvent() { + return mIsQuickEvent; + } + + public boolean isDeviceIntroCompleted() { + return mIsFirstTimeDone; + } + + public String getTitle() { + return mEventTitle; + } + + public String getActionTitle() { + return mEventTitleSub; + } + + public String getClockExt() { + return mClockExt; + } + + public String getGreetings() { + return mGreetings; + } + + public OnClickListener getAction() { + return mEventTitleSubAction; + } + + public int getActionIcon() { + return mEventSubIcon; + } + + public int getLuckyNumber(int max) { + return getLuckyNumber(0, max); + } + + public int getLuckyNumber(int min, int max) { + Random r = new Random(); + return r.nextInt((max - min) + 1) + min; + } + + public void setMediaInfo(String title, String artist, boolean clientLost, boolean activePlayback) { + mNowPlayingTitle = title; + mNowPlayingArtist = artist; + mClientLost = clientLost; + mPlayingActive = activePlayback; + } + + public boolean isNowPlaying() { + return mPlayingActive && Utilities.isQuickspaceNowPlaying(mContext); + } + + public void onPause() { + mRunning = false; + unregisterPSAListener(); + } + + public void onResume() { + mRunning = true; + registerPSAListener(); + } +} diff --git a/src/com/android/launcher3/quickspace/QuickSpaceView.java b/src/com/android/launcher3/quickspace/QuickSpaceView.java new file mode 100644 index 00000000000..7902cd96db5 --- /dev/null +++ b/src/com/android/launcher3/quickspace/QuickSpaceView.java @@ -0,0 +1,291 @@ +/* + * Copyright (C) 2018-2023 crDroid Android 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.quickspace; + +import android.animation.LayoutTransition; +import android.animation.ValueAnimator; +import android.animation.ValueAnimator.AnimatorUpdateListener; +import android.content.ActivityNotFoundException; +import android.content.ComponentName; +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.res.ColorStateList; +import android.text.TextUtils.TruncateAt; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import com.android.launcher3.BubbleTextView; +import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.R; +import com.android.launcher3.Utilities; +import com.android.launcher3.util.Themes; + +import com.android.launcher3.quickspace.QuickspaceController.OnDataListener; +import com.android.launcher3.quickspace.receivers.QuickSpaceActionReceiver; +import com.android.launcher3.quickspace.views.DateTextView; + +public class QuickSpaceView extends FrameLayout implements AnimatorUpdateListener, OnDataListener { + + private static final String TAG = "Launcher3:QuickSpaceView"; + private static final boolean DEBUG = false; + + public final ColorStateList mColorStateList; + public BubbleTextView mBubbleTextView; + public final int mQuickspaceBackgroundRes; + + public ViewGroup mQuickspaceContent; + public ImageView mEventSubIcon; + public TextView mEventTitleSub; + public TextView mEventTitleSubColored; + public TextView mGreetingsExt; + public TextView mGreetingsExtClock; + public ViewGroup mWeatherContentSub; + public ImageView mWeatherIconSub; + public TextView mWeatherTempSub; + public TextView mEventTitle; + + public boolean mIsQuickEvent; + public boolean mFinishedInflate; + public boolean mWeatherAvailable; + public boolean mAttached; + + private QuickSpaceActionReceiver mActionReceiver; + public QuickspaceController mController; + + public QuickSpaceView(Context context, AttributeSet set) { + super(context, set); + mActionReceiver = new QuickSpaceActionReceiver(context); + mController = new QuickspaceController(context); + mColorStateList = ColorStateList.valueOf(Themes.getAttrColor(getContext(), R.attr.workspaceTextColor)); + mQuickspaceBackgroundRes = R.drawable.bg_quickspace; + setClipChildren(false); + } + + @Override + public void onDataUpdated() { + boolean altUI = Utilities.useAlternativeQuickspaceUI(getContext()); + mController.getEventController().initQuickEvents(); + mIsQuickEvent = mController.isQuickEvent(); + if (mEventTitle == null || (altUI && mGreetingsExt == null)) { + prepareLayout(altUI); + } + mWeatherAvailable = mController.isWeatherAvailable() && + mController.getEventController().isDeviceIntroCompleted(); + loadDoubleLine(altUI); + } + + private final void loadDoubleLine(boolean useAlternativeQuickspaceUI) { + setBackgroundResource(mQuickspaceBackgroundRes); + mEventTitle.setText(mController.getEventController().getTitle()); + if (useAlternativeQuickspaceUI) { + if (!mController.getEventController().getGreetings().isEmpty()) { + mGreetingsExt.setVisibility(View.VISIBLE); + mGreetingsExt.setText(mController.getEventController().getGreetings()); + mGreetingsExt.setEllipsize(TruncateAt.END); + mGreetingsExt.setOnClickListener(mController.getEventController().getAction()); + } else { + mGreetingsExt.setVisibility(View.GONE); + } + if (!mController.getEventController().getClockExt().isEmpty()) { + mGreetingsExtClock.setVisibility(View.VISIBLE); + mGreetingsExtClock.setText(mController.getEventController().getClockExt()); + mGreetingsExtClock.setOnClickListener(mController.getEventController().getAction()); + } else { + mGreetingsExtClock.setVisibility(View.GONE); + } + } + if (mIsQuickEvent && (Utilities.isQuickspacePersonalityEnabled(getContext()) || + mController.getEventController().isNowPlaying())) { + mEventTitle.setEllipsize(TruncateAt.MARQUEE); + mEventTitle.setMarqueeRepeatLimit(3); + mEventTitle.setSelected(true); + mEventTitle.setOnClickListener(mController.getEventController().getAction()); + mEventTitleSub.setVisibility(View.VISIBLE); + mEventTitleSub.setText(mController.getEventController().getActionTitle()); + mEventTitleSub.setEllipsize(TruncateAt.MARQUEE); + mEventTitleSub.setMarqueeRepeatLimit(3); + mEventTitleSub.setSelected(true); + mEventTitleSub.setOnClickListener(mController.getEventController().getAction()); + if (useAlternativeQuickspaceUI) { + if (mController.getEventController().isNowPlaying()) { + mEventSubIcon.setVisibility(View.GONE); + mEventTitleSub.setOnClickListener(mController.getEventController().getAction()); + mEventTitleSubColored.setVisibility(View.VISIBLE); + mEventTitleSubColored.setText(getContext().getString(R.string.qe_now_playing_by)); + mEventTitleSubColored.setOnClickListener(mController.getEventController().getAction()); + } else { + setEventSubIcon(); + mEventTitleSubColored.setText(""); + mEventTitleSubColored.setVisibility(View.GONE); + } + } else { + setEventSubIcon(); + } + } else { + mEventTitleSub.setVisibility(View.GONE); + mEventSubIcon.setVisibility(View.GONE); + if (useAlternativeQuickspaceUI) { + mEventTitleSubColored.setVisibility(View.GONE); + } + } + bindWeather(mWeatherContentSub, mWeatherTempSub, mWeatherIconSub); + } + + private void setEventSubIcon() { + int icon = mController.getEventController().getActionIcon(); + if (icon > 0) { + mEventSubIcon.setVisibility(View.VISIBLE); + mEventSubIcon.setImageTintList(mColorStateList); + mEventSubIcon.setImageResource(mController.getEventController().getActionIcon()); + mEventSubIcon.setOnClickListener(mController.getEventController().getAction()); + } else { + mEventSubIcon.setVisibility(View.GONE); + } + } + + private final void bindWeather(View container, TextView title, ImageView icon) { + if (!mWeatherAvailable || mController.getEventController().isNowPlaying()) { + container.setVisibility(View.GONE); + return; + } + String weatherTemp = mController.getWeatherTemp(); + if (weatherTemp == null || weatherTemp.isEmpty()) { + container.setVisibility(View.GONE); + return; + } + boolean hasGoogleApp = isPackageEnabled("com.google.android.googlequicksearchbox", getContext()); + container.setVisibility(View.VISIBLE); + container.setOnClickListener(hasGoogleApp ? mActionReceiver.getWeatherAction() : null); + title.setText(weatherTemp); + icon.setImageDrawable(mController.getWeatherIcon()); + } + + private final void loadViews() { + mEventTitle = (TextView) findViewById(R.id.quick_event_title); + mEventTitleSub = (TextView) findViewById(R.id.quick_event_title_sub); + mEventTitleSubColored = (TextView) findViewById(R.id.quick_event_title_sub_colored); + mEventSubIcon = (ImageView) findViewById(R.id.quick_event_icon_sub); + mWeatherIconSub = (ImageView) findViewById(R.id.quick_event_weather_icon); + mQuickspaceContent = (ViewGroup) findViewById(R.id.quickspace_content); + mWeatherContentSub = (ViewGroup) findViewById(R.id.quick_event_weather_content); + mWeatherTempSub = (TextView) findViewById(R.id.quick_event_weather_temp); + if (Utilities.useAlternativeQuickspaceUI(getContext())) { + mGreetingsExtClock = (TextView) findViewById(R.id.extended_greetings_clock); + mGreetingsExt = (TextView) findViewById(R.id.extended_greetings); + } + } + + private void prepareLayout(boolean useAlternativeQuickspaceUI) { + int indexOfChild = indexOfChild(mQuickspaceContent); + removeView(mQuickspaceContent); + if (useAlternativeQuickspaceUI) { + addView(LayoutInflater.from(getContext()).inflate(R.layout.quickspace_alternate_double, this, false), indexOfChild); + } else { + addView(LayoutInflater.from(getContext()).inflate(R.layout.quickspace_doubleline, this, false), indexOfChild); + } + + loadViews(); + getQuickSpaceView(); + } + + private void getQuickSpaceView() { + if (mQuickspaceContent.getVisibility() != View.VISIBLE) { + mQuickspaceContent.setVisibility(View.VISIBLE); + mQuickspaceContent.setAlpha(0.0f); + mQuickspaceContent.animate().setDuration(200).alpha(1.0f); + } + } + + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + invalidate(); + } + + @Override + public void onAttachedToWindow() { + super.onAttachedToWindow(); + if (mAttached) + return; + + mAttached = true; + if (mController != null && mFinishedInflate) { + mController.addListener(this); + } + } + + @Override + public void onDetachedFromWindow() { + super.onDetachedFromWindow(); + if (!mAttached) + return; + + mAttached = false; + if (mController != null) { + mController.removeListener(this); + } + } + + public boolean isPackageEnabled(String pkgName, Context context) { + try { + return context.getPackageManager().getApplicationInfo(pkgName, 0).enabled; + } catch (PackageManager.NameNotFoundException e) { + return false; + } + } + + @Override + public void onFinishInflate() { + super.onFinishInflate(); + loadViews(); + mFinishedInflate = true; + mBubbleTextView = findViewById(R.id.dummyBubbleTextView); + mBubbleTextView.setTag(new ItemInfo() { + @Override + public ComponentName getTargetComponent() { + return new ComponentName(getContext(), ""); + } + }); + mBubbleTextView.setContentDescription(""); + if (isAttachedToWindow()) { + if (mController != null) { + mController.addListener(this); + } + } + } + + @Override + public void onLayout(boolean b, int n, int n2, int n3, int n4) { + super.onLayout(b, n, n2, n3, n4); + } + + public void onPause() { + mController.onPause(); + } + + public void onResume() { + mController.onResume(); + } + + public void setPadding(int n, int n2, int n3, int n4) { + super.setPadding(0, 0, 0, 0); + } + +} diff --git a/src/com/android/launcher3/quickspace/QuickspaceController.java b/src/com/android/launcher3/quickspace/QuickspaceController.java new file mode 100644 index 00000000000..c7dae879b8f --- /dev/null +++ b/src/com/android/launcher3/quickspace/QuickspaceController.java @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2018 CypherOS + * + * 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.quickspace; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.Icon; +import android.media.AudioManager; +import android.media.MediaMetadataRetriever; +import android.media.RemoteControlClient; +import android.media.RemoteController; +import android.os.Handler; +import android.service.notification.StatusBarNotification; +import android.util.Log; + +import com.android.internal.util.derp.OmniJawsClient; + +import com.android.launcher3.R; +import com.android.launcher3.Utilities; +import com.android.launcher3.notification.NotificationKeyData; +import com.android.launcher3.notification.NotificationListener; +import com.android.launcher3.util.PackageUserKey; + +import java.util.ArrayList; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import java.util.List; + +public class QuickspaceController implements NotificationListener.NotificationsChangedListener, OmniJawsClient.OmniJawsObserver { + + public final ArrayList mListeners = new ArrayList(); + private static final String SETTING_WEATHER_LOCKSCREEN_UNIT = "weather_lockscreen_unit"; + private static final boolean DEBUG = false; + private static final String TAG = "Launcher3:QuickspaceController"; + + private final Context mContext; + private final Handler mHandler; + private QuickEventsController mEventsController; + private OmniJawsClient mWeatherClient; + private OmniJawsClient.WeatherInfo mWeatherInfo; + private Drawable mConditionImage; + + private boolean mUseImperialUnit; + + private AudioManager mAudioManager; + private Metadata mMetadata = new Metadata(); + private RemoteController mRemoteController; + private boolean mClientLost = true; + private boolean mMediaActive = false; + private ExecutorService executorService = Executors.newSingleThreadExecutor(); + + public interface OnDataListener { + void onDataUpdated(); + } + + public QuickspaceController(Context context) { + mContext = context; + mHandler = new Handler(); + mEventsController = new QuickEventsController(context); + mWeatherClient = new OmniJawsClient(context); + mRemoteController = new RemoteController(context, mRCClientUpdateListener); + mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + mAudioManager.registerRemoteController(mRemoteController); + } + + private void addWeatherProvider() { + if (!Utilities.isQuickspaceWeather(mContext)) return; + mWeatherClient.addObserver(this); + queryAndUpdateWeather(); + } + + public void addListener(OnDataListener listener) { + mListeners.add(listener); + addWeatherProvider(); + listener.onDataUpdated(); + } + + public void removeListener(OnDataListener listener) { + if (mWeatherClient != null) { + mWeatherClient.removeObserver(this); + } + mListeners.remove(listener); + } + + public boolean isQuickEvent() { + return mEventsController.isQuickEvent(); + } + + public QuickEventsController getEventController() { + return mEventsController; + } + + public boolean isWeatherAvailable() { + return mWeatherClient != null && mWeatherClient.isOmniJawsEnabled(); + } + + public Drawable getWeatherIcon() { + return mConditionImage; + } + + public String getWeatherTemp() { + boolean shouldShowCity = Utilities.QuickSpaceShowCity(mContext); + boolean showWeatherText = Utilities.QuickSpaceShowWeatherText(mContext); + if (mWeatherInfo != null) { + String formattedCondition = mWeatherInfo.condition; + if (formattedCondition.toLowerCase().contains("clouds")) { + formattedCondition = mContext.getResources().getString(R.string.quick_event_weather_clouds); + } else if (formattedCondition.toLowerCase().contains("rain")) { + formattedCondition = mContext.getResources().getString(R.string.quick_event_weather_rain); + } else if (formattedCondition.toLowerCase().contains("clear")) { + formattedCondition = mContext.getResources().getString(R.string.quick_event_weather_clear); + } else if (formattedCondition.toLowerCase().contains("storm")) { + formattedCondition = mContext.getResources().getString(R.string.quick_event_weather_storm); + } else if (formattedCondition.toLowerCase().contains("snow")) { + formattedCondition = mContext.getResources().getString(R.string.quick_event_weather_snow); + } else if (formattedCondition.toLowerCase().contains("wind")) { + formattedCondition = mContext.getResources().getString(R.string.quick_event_weather_wind); + } else if (formattedCondition.toLowerCase().contains("mist")) { + formattedCondition = mContext.getResources().getString(R.string.quick_event_weather_mist); + } + String weatherTemp = (shouldShowCity ? mWeatherInfo.city : "") + " " + mWeatherInfo.temp + + mWeatherInfo.tempUnits + (showWeatherText ? " · " + formattedCondition : ""); + return weatherTemp; + } + return null; + } + + private void playbackStateUpdate(int state) { + boolean active; + switch (state) { + case RemoteControlClient.PLAYSTATE_PLAYING: + active = true; + break; + case RemoteControlClient.PLAYSTATE_ERROR: + case RemoteControlClient.PLAYSTATE_PAUSED: + default: + active = false; + break; + } + if (active != mMediaActive) { + mMediaActive = active; + } + updateMediaInfo(); + } + + public void updateMediaInfo() { + if (mEventsController != null) { + mEventsController.setMediaInfo(mMetadata.trackTitle, mMetadata.trackArtist, mClientLost, mMediaActive); + mEventsController.updateQuickEvents(); + notifyListeners(); + } + } + + @Override + public void onNotificationPosted(PackageUserKey postedPackageUserKey, + NotificationKeyData notificationKey) { + updateMediaInfo(); + } + + @Override + public void onNotificationRemoved(PackageUserKey removedPackageUserKey, + NotificationKeyData notificationKey) { + updateMediaInfo(); + } + + @Override + public void onNotificationFullRefresh(List activeNotifications) { + updateMediaInfo(); + } + + public void onPause() { + if (mEventsController != null) mEventsController.onPause(); + } + + public void onResume() { + if (mEventsController != null) { + updateMediaInfo(); + mEventsController.onResume(); + notifyListeners(); + } + } + + @Override + public void weatherUpdated() { + queryAndUpdateWeather(); + } + + @Override + public void weatherError(int errorReason) { + Log.d(TAG, "weatherError " + errorReason); + if (errorReason == OmniJawsClient.EXTRA_ERROR_DISABLED) { + mWeatherInfo = null; + notifyListeners(); + } + } + + @Override + public void updateSettings() { + Log.i(TAG, "updateSettings"); + queryAndUpdateWeather(); + } + + private void queryAndUpdateWeather() { + executorService.execute(new Runnable() { + @Override + public void run() { + try { + mWeatherClient.queryWeather(); + mWeatherInfo = mWeatherClient.getWeatherInfo(); + if (mWeatherInfo != null) { + mConditionImage = mWeatherClient.getWeatherConditionImage(mWeatherInfo.conditionCode); + } + notifyListeners(); + } catch(Exception e) { + // Do nothing + } + } + }); + } + + public void notifyListeners() { + mHandler.post(new Runnable() { + @Override + public void run() { + for (OnDataListener list : mListeners) { + list.onDataUpdated(); + } + } + }); + } + + private RemoteController.OnClientUpdateListener mRCClientUpdateListener = + new RemoteController.OnClientUpdateListener() { + + @Override + public void onClientChange(boolean clearing) { + if (clearing) { + mMetadata.clear(); + mMediaActive = false; + mClientLost = true; + } + updateMediaInfo(); + } + + @Override + public void onClientPlaybackStateUpdate(int state, long stateChangeTimeMs, + long currentPosMs, float speed) { + mClientLost = false; + playbackStateUpdate(state); + } + + @Override + public void onClientPlaybackStateUpdate(int state) { + mClientLost = false; + playbackStateUpdate(state); + } + + @Override + public void onClientMetadataUpdate(RemoteController.MetadataEditor data) { + mMetadata.trackTitle = data.getString(MediaMetadataRetriever.METADATA_KEY_TITLE, + mMetadata.trackTitle); + mMetadata.trackArtist = data.getString(MediaMetadataRetriever.METADATA_KEY_ARTIST, + mMetadata.trackArtist); + mClientLost = false; + updateMediaInfo(); + } + + @Override + public void onClientTransportControlUpdate(int transportControlFlags) { + } + }; + + class Metadata { + private String trackTitle; + private String trackArtist; + + public void clear() { + trackTitle = null; + trackArtist = null; + } + } +} diff --git a/src/com/android/launcher3/quickspace/receivers/QuickSpaceActionReceiver.java b/src/com/android/launcher3/quickspace/receivers/QuickSpaceActionReceiver.java new file mode 100644 index 00000000000..e67645ae60b --- /dev/null +++ b/src/com/android/launcher3/quickspace/receivers/QuickSpaceActionReceiver.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2018-2023 crDroid Android 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.quickspace.receivers; + +import android.content.ActivityNotFoundException; +import android.content.ComponentName; +import android.content.ContentUris; +import android.content.Context; +import android.content.Intent; +import android.content.pm.LauncherApps; +import android.net.Uri; +import android.os.Process; +import android.os.UserHandle; +import android.provider.CalendarContract; +import android.view.View; +import android.view.View.OnClickListener; + +import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.R; +import com.android.launcher3.Utilities; + +public class QuickSpaceActionReceiver { + + private static Context mContext; + private final LauncherApps mLauncherApps; + + public OnClickListener mCalendarClickListener; + public OnClickListener mWeatherClickListener; + + public QuickSpaceActionReceiver(Context context) { + mContext = context; + mLauncherApps = context.getSystemService(LauncherApps.class); + + mCalendarClickListener = new OnClickListener() { + @Override + public void onClick(View view) { + openGoogleCalendar(view); + } + }; + + mWeatherClickListener = new OnClickListener() { + @Override + public void onClick(View view) { + openGoogleWeather(view); + } + }; + } + + private void openGoogleCalendar(View view) { + final Uri content_URI = CalendarContract.CONTENT_URI; + final Uri.Builder appendPath = content_URI.buildUpon().appendPath("time"); + ContentUris.appendId(appendPath, System.currentTimeMillis()); + final Intent addFlags = new Intent(Intent.ACTION_VIEW) + .setData(appendPath.build()) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + try { + Launcher.getLauncher(mContext).startActivitySafely(view, addFlags, null); + } catch (ActivityNotFoundException ex) { + mLauncherApps.startAppDetailsActivity(new ComponentName("com.google.android.googlequicksearchbox", ""), Process.myUserHandle(), null, null); + } + } + + private void openGoogleWeather(View view) { + Intent intent = new Intent("android.intent.action.VIEW"); + intent.setData(Uri.parse("dynact://velour/weather/ProxyActivity")); + intent.setComponent(new ComponentName("com.google.android.googlequicksearchbox", "com.google.android.apps.gsa.velour.DynamicActivityTrampoline")); + try { + Launcher.getLauncher(mContext).startActivitySafely(view, intent, null); + } catch (ActivityNotFoundException ex) { + mLauncherApps.startAppDetailsActivity(new ComponentName("com.google.android.googlequicksearchbox", + "com.google.android.apps.gsa.velour.DynamicActivityTrampoline"), Process.myUserHandle(), null, null); + } + } + + public OnClickListener getCalendarAction() { + return mCalendarClickListener; + } + + public OnClickListener getWeatherAction() { + return mWeatherClickListener; + } +} diff --git a/src/com/android/launcher3/quickspace/views/DateTextView.java b/src/com/android/launcher3/quickspace/views/DateTextView.java new file mode 100644 index 00000000000..015ce71459d --- /dev/null +++ b/src/com/android/launcher3/quickspace/views/DateTextView.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2018-2023 crDroid Android 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.quickspace.views; + +import android.annotation.TargetApi; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.icu.text.DateFormat; +import android.icu.text.DisplayContext; +import android.text.format.DateUtils; +import android.util.AttributeSet; + +import com.android.launcher3.R; +import com.android.launcher3.Utilities; + +import java.util.Locale; + +public class DateTextView extends DoubleShadowTextView { + + private DateFormat mDateFormat; + private final BroadcastReceiver mTimeChangeReceiver; + private boolean mIsVisible = false; + + public DateTextView(final Context context) { + this(context, null); + } + + public DateTextView(final Context context, final AttributeSet set) { + super(context, set, 0); + mTimeChangeReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + reloadDateFormat(!Intent.ACTION_TIME_TICK.equals(intent.getAction())); + } + }; + } + + public void reloadDateFormat(boolean forcedChange) { + String format; + if (mDateFormat == null || forcedChange) { + String styleText; + Context context = getContext(); + if (Utilities.useAlternativeQuickspaceUI(context)) { + styleText = context.getString(R.string.quickspace_date_format_minimalistic); + } else { + styleText = context.getString(R.string.quickspace_date_format); + } + mDateFormat = DateFormat.getInstanceForSkeleton(styleText, Locale.getDefault()); + mDateFormat.setContext(DisplayContext.CAPITALIZATION_FOR_STANDALONE); + } + format = mDateFormat.format(System.currentTimeMillis()); + setText(format); + setContentDescription(format); + } + + private void registerReceiver() { + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(Intent.ACTION_TIME_TICK); + intentFilter.addAction(Intent.ACTION_TIME_CHANGED); + intentFilter.addAction(Intent.ACTION_TIMEZONE_CHANGED); + getContext().registerReceiver(mTimeChangeReceiver, intentFilter, Context.RECEIVER_NOT_EXPORTED); + } + + private void unregisterReceiver() { + getContext().unregisterReceiver(mTimeChangeReceiver); + } + + public void onVisibilityAggregated(boolean isVisible) { + super.onVisibilityAggregated(isVisible); + if (!mIsVisible && isVisible) { + mIsVisible = true; + registerReceiver(); + reloadDateFormat(true); + } else if (mIsVisible && !isVisible) { + unregisterReceiver(); + mIsVisible = false; + } + } +} diff --git a/src/com/android/launcher3/quickspace/views/DoubleShadowTextView.java b/src/com/android/launcher3/quickspace/views/DoubleShadowTextView.java new file mode 100644 index 00000000000..1bf019f0d6b --- /dev/null +++ b/src/com/android/launcher3/quickspace/views/DoubleShadowTextView.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2018-2023 crDroid Android 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.quickspace.views; + +import android.content.Context; +import android.graphics.Canvas; +import android.util.AttributeSet; +import android.widget.TextView; + +import com.android.launcher3.views.DoubleShadowBubbleTextView; + +public class DoubleShadowTextView extends TextView { + + private final DoubleShadowBubbleTextView.ShadowInfo mShadowInfo; + + public DoubleShadowTextView(Context context) { + this(context, null); + } + + public DoubleShadowTextView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public DoubleShadowTextView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + mShadowInfo = new DoubleShadowBubbleTextView.ShadowInfo(context, attrs, defStyleAttr); + setShadowLayer(Math.max(mShadowInfo.keyShadowBlur + mShadowInfo.keyShadowOffsetX, mShadowInfo.ambientShadowBlur), 0f, 0f, mShadowInfo.keyShadowColor); + } + + protected void onDraw(Canvas canvas) { + if (mShadowInfo.skipDoubleShadow(this)) { + super.onDraw(canvas); + return; + } + getPaint().setShadowLayer(mShadowInfo.ambientShadowBlur, 0.0f, 0.0f, mShadowInfo.ambientShadowColor); + super.onDraw(canvas); + getPaint().setShadowLayer(mShadowInfo.keyShadowBlur, 0.0f, mShadowInfo.keyShadowOffsetX, mShadowInfo.keyShadowColor); + super.onDraw(canvas); + } +} diff --git a/src/com/android/launcher3/settings/SettingsHomescreen.java b/src/com/android/launcher3/settings/SettingsHomescreen.java index dea4e35c105..83c44ee9a82 100644 --- a/src/com/android/launcher3/settings/SettingsHomescreen.java +++ b/src/com/android/launcher3/settings/SettingsHomescreen.java @@ -46,6 +46,8 @@ import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity; +import com.android.internal.util.derp.OmniJawsClient; + public class SettingsHomescreen extends CollapsingToolbarBaseActivity implements OnPreferenceStartFragmentCallback, OnPreferenceStartScreenCallback, SharedPreferences.OnSharedPreferenceChangeListener{ @@ -109,6 +111,13 @@ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, Strin case Utilities.KEY_HOTSEAT_OPACITY: case Utilities.KEY_SHORT_PARALLAX: case Utilities.KEY_SINGLE_PAGE_CENTER: + case Utilities.DESKTOP_SHOW_QUICKSPACE: + case Utilities.KEY_SHOW_ALT_QUICKSPACE: + case Utilities.KEY_SHOW_QUICKSPACE_NOWPLAYING: + case Utilities.KEY_SHOW_QUICKSPACE_WEATHER: + case Utilities.KEY_SHOW_QUICKSPACE_PSONALITY: + case Utilities.KEY_SHOW_QUICKSPACE_WEATHER_CITY: + case Utilities.KEY_SHOW_QUICKSPACE_WEATHER_TEXT: LauncherAppState.getInstanceNoCreate().setNeedsRestart(); break; default: @@ -168,6 +177,9 @@ public static class HomescreenSettingsFragment extends PreferenceFragmentCompat private Preference mShowGoogleAppPref; private Preference mShowGoogleBarPref; + private Preference mWeatherPref; + + private OmniJawsClient mWeatherClient; @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { @@ -193,6 +205,13 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { mShowGoogleBarPref = screen.findPreference(Utilities.KEY_DOCK_SEARCH); updateIsGoogleAppEnabled(); + mWeatherClient = new OmniJawsClient(getContext()); + mWeatherPref = getPreferenceScreen().findPreference(Utilities.KEY_SHOW_QUICKSPACE_WEATHER); + if (!mWeatherClient.isOmniJawsEnabled()) { + mWeatherPref.setEnabled(false); + mWeatherPref.setSummary(R.string.quick_event_ambient_weather_enabled_info); + } + if (getActivity() != null && !TextUtils.isEmpty(getPreferenceScreen().getTitle())) { getActivity().setTitle(getPreferenceScreen().getTitle()); } From 7300cbad47ef45c8b7144d5d24e7c0540a48e740 Mon Sep 17 00:00:00 2001 From: SakuraiLH Date: Sat, 24 Dec 2022 03:48:42 +0000 Subject: [PATCH 02/19] DerpLauncher: Bring back 4x4 grid option --- res/values/dimens.xml | 2 + res/xml/default_workspace_4x4.xml | 135 ++++++++++++++++++++++++++++++ res/xml/device_profiles.xml | 64 ++++++++++++++ 3 files changed, 201 insertions(+) create mode 100644 res/xml/default_workspace_4x4.xml diff --git a/res/values/dimens.xml b/res/values/dimens.xml index f2dc189e774..32a218af51e 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -406,6 +406,8 @@ 0dp 0dp 0dp + 0dp + 0dp 0dp diff --git a/res/xml/default_workspace_4x4.xml b/res/xml/default_workspace_4x4.xml new file mode 100644 index 00000000000..7a743f398ad --- /dev/null +++ b/res/xml/default_workspace_4x4.xml @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/xml/device_profiles.xml b/res/xml/device_profiles.xml index 9ec56fa63a8..ab9534ef3db 100644 --- a/res/xml/device_profiles.xml +++ b/res/xml/device_profiles.xml @@ -93,6 +93,70 @@ + + + + + + + + + + + + + + Date: Fri, 2 Feb 2024 14:21:23 +0800 Subject: [PATCH 03/19] DerpLauncher: Set app drawer opacity to 91 * any value below 91, will make the status bar icons look bad in white theme Change-Id: I0570dc05dad82fb3ed75c376ba3e6510a5b89a84 Signed-off-by: clarencelol --- res/xml/launcher_app_drawer_preferences.xml | 2 +- src/com/android/launcher3/Utilities.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/res/xml/launcher_app_drawer_preferences.xml b/res/xml/launcher_app_drawer_preferences.xml index 2eefa914a2d..187556c46e1 100644 --- a/res/xml/launcher_app_drawer_preferences.xml +++ b/res/xml/launcher_app_drawer_preferences.xml @@ -65,6 +65,6 @@ android:max="100" android:min="0" settings:units="%" - android:defaultValue="80" /> + android:defaultValue="91" /> diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index cf6ff91e720..2dee56b79c2 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -1011,7 +1011,7 @@ public static int getRecentsOpacity(Context context) { public static int getAllAppsOpacity(Context context) { SharedPreferences prefs = LauncherPrefs.getPrefs(context.getApplicationContext()); - return prefs.getInt(KEY_APP_DRAWER_OPACITY, 80); + return prefs.getInt(KEY_APP_DRAWER_OPACITY, 91); } public static boolean isShowMeminfo(Context context) { From 0f80d2bfd44f002fd40892bdb9aa5dedb69a4f95 Mon Sep 17 00:00:00 2001 From: Alvin Francis Date: Thu, 2 Nov 2023 00:46:35 -0400 Subject: [PATCH 04/19] DerpLauncher: Allow the blur to be completely disabled Change-Id: I039180cea33a8c2bdc46fd9c9b3eea785bba0f24 Signed-off-by: Alvin Francis --- res/xml/launcher_misc_preferences.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/xml/launcher_misc_preferences.xml b/res/xml/launcher_misc_preferences.xml index cbf0b438240..2f53750a333 100644 --- a/res/xml/launcher_misc_preferences.xml +++ b/res/xml/launcher_misc_preferences.xml @@ -46,7 +46,7 @@ android:title="@string/background_blur_title" android:summary="@string/background_blur_summary" android:persistent="true" - android:max="175" + android:max="225" android:min="0" settings:units="px" android:defaultValue="23" /> From e81f8aeb69c7595dbce5e493f58230bfa30e68a7 Mon Sep 17 00:00:00 2001 From: Pranav Vashi Date: Sun, 9 Apr 2023 16:59:03 +0530 Subject: [PATCH 05/19] DerpLauncher: Follow all apps background for taskbar slide in view Signed-off-by: Pranav Vashi --- .../launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java | 1 + 1 file changed, 1 insertion(+) diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java index 6c2a44e0fa0..a0f46dff5e4 100644 --- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java +++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java @@ -35,6 +35,7 @@ import com.android.launcher3.DeviceProfile; import com.android.launcher3.Insettable; import com.android.launcher3.R; +import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatorListeners; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.Utilities; From d2cc698b7babdb69aca62339e7a768cf70c91efd Mon Sep 17 00:00:00 2001 From: Ido Ben-Hur Date: Fri, 5 Apr 2024 13:11:53 +0300 Subject: [PATCH 06/19] DerpLauncher: QuickstepAtomicAnimationFactory: Add null checks to prevent NPE Solves the following crash on exiting recents when nothing is on any home screen: FATAL EXCEPTION: main Process: com.android.launcher3, PID: 7671 java.lang.NullPointerException: Attempt to invoke virtual method 'int android.view.ViewGroup.getVisibility()' on a null object reference at com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory.prepareForAtomicAnimation(go/retraceme d64815e9bb1a1e22c3f9643b1a3046dfb4cece8716c9ab9e81a56f1b7725d51a:303) at com.android.launcher3.statemanager.StateManager.goToStateAnimated(go/retraceme d64815e9bb1a1e22c3f9643b1a3046dfb4cece8716c9ab9e81a56f1b7725d51a:26) at com.android.launcher3.statemanager.StateManager.goToState(go/retraceme d64815e9bb1a1e22c3f9643b1a3046dfb4cece8716c9ab9e81a56f1b7725d51a:23) at com.android.launcher3.statemanager.StateManager.goToState(go/retraceme d64815e9bb1a1e22c3f9643b1a3046dfb4cece8716c9ab9e81a56f1b7725d51a:2) at com.android.quickstep.views.LauncherRecentsView.handleStartHome(go/retraceme d64815e9bb1a1e22c3f9643b1a3046dfb4cece8716c9ab9e81a56f1b7725d51a:16) at com.android.quickstep.views.RecentsView.startHome(go/retraceme d64815e9bb1a1e22c3f9643b1a3046dfb4cece8716c9ab9e81a56f1b7725d51a:3) at com.android.quickstep.views.RecentsView.startHome(go/retraceme d64815e9bb1a1e22c3f9643b1a3046dfb4cece8716c9ab9e81a56f1b7725d51a:1) at com.android.quickstep.views.RecentsView$21.onEnd(go/retraceme d64815e9bb1a1e22c3f9643b1a3046dfb4cece8716c9ab9e81a56f1b7725d51a:394) at com.android.quickstep.views.RecentsView$21.accept(go/retraceme d64815e9bb1a1e22c3f9643b1a3046dfb4cece8716c9ab9e81a56f1b7725d51a:4) at com.android.quickstep.views.RecentsView$21.accept(go/retraceme d64815e9bb1a1e22c3f9643b1a3046dfb4cece8716c9ab9e81a56f1b7725d51a:1) at com.android.launcher3.anim.AnimatorListeners$EndStateCallbackWrapper.onAnimationEnd(go/retraceme d64815e9bb1a1e22c3f9643b1a3046dfb4cece8716c9ab9e81a56f1b7725d51a:32) at com.android.launcher3.anim.AnimatorPlaybackController$$ExternalSyntheticLambda0.accept(go/retraceme d64815e9bb1a1e22c3f9643b1a3046dfb4cece8716c9ab9e81a56f1b7725d51a:14) at com.android.launcher3.anim.AnimatorPlaybackController.$r8$lambda$bF6fu10ogo158poE8C5B_R0HpFg(go/retraceme d64815e9bb1a1e22c3f9643b1a3046dfb4cece8716c9ab9e81a56f1b7725d51a:27) at com.android.launcher3.anim.AnimatorPlaybackController$$ExternalSyntheticLambda3.accept(go/retraceme d64815e9bb1a1e22c3f9643b1a3046dfb4cece8716c9ab9e81a56f1b7725d51a:12) at com.android.launcher3.anim.AnimatorPlaybackController.callAnimatorCommandRecursively(go/retraceme d64815e9bb1a1e22c3f9643b1a3046dfb4cece8716c9ab9e81a56f1b7725d51a:1) at com.android.launcher3.anim.AnimatorPlaybackController.callAnimatorCommandRecursively(go/retraceme d64815e9bb1a1e22c3f9643b1a3046dfb4cece8716c9ab9e81a56f1b7725d51a:36) at com.android.launcher3.anim.AnimatorPlaybackController.callListenerCommandRecursively(go/retraceme d64815e9bb1a1e22c3f9643b1a3046dfb4cece8716c9ab9e81a56f1b7725d51a:7) at com.android.launcher3.anim.AnimatorPlaybackController.dispatchOnEnd(go/retraceme d64815e9bb1a1e22c3f9643b1a3046dfb4cece8716c9ab9e81a56f1b7725d51a:9) at com.android.launcher3.anim.AnimatorPlaybackController$OnAnimationEndDispatcher.onAnimationSuccess(go/retraceme d64815e9bb1a1e22c3f9643b1a3046dfb4cece8716c9ab9e81a56f1b7725d51a:7) at com.android.launcher3.anim.AnimationSuccessListener.onAnimationEnd(go/retraceme d64815e9bb1a1e22c3f9643b1a3046dfb4cece8716c9ab9e81a56f1b7725d51a:5) ... --- .../states/QuickstepAtomicAnimationFactory.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java index 6651c7399e4..4407afdd9fd 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java @@ -149,20 +149,21 @@ public void prepareForAtomicAnimation(LauncherState fromState, LauncherState toS Workspace workspace = mActivity.getWorkspace(); // Start from a higher workspace scale, but only if we're invisible so we don't jump. - boolean isWorkspaceVisible = workspace.getVisibility() == VISIBLE; + boolean isWorkspaceVisible = workspace != null && workspace.getVisibility() == VISIBLE; if (isWorkspaceVisible) { CellLayout currentChild = (CellLayout) workspace.getChildAt( workspace.getCurrentPage()); - isWorkspaceVisible = currentChild.getVisibility() == VISIBLE + isWorkspaceVisible = currentChild != null && currentChild.getVisibility() == VISIBLE && currentChild.getShortcutsAndWidgets().getAlpha() > 0; } - if (!isWorkspaceVisible) { + if (!isWorkspaceVisible && workspace != null) { workspace.setScaleX(WORKSPACE_PREPARE_SCALE); workspace.setScaleY(WORKSPACE_PREPARE_SCALE); } Hotseat hotseat = mActivity.getHotseat(); - boolean isHotseatVisible = hotseat.getVisibility() == VISIBLE && hotseat.getAlpha() > 0; - if (!isHotseatVisible) { + boolean isHotseatVisible = hotseat != null + && hotseat.getVisibility() == VISIBLE && hotseat.getAlpha() > 0; + if (!isHotseatVisible && hotseat != null) { hotseat.setScaleX(WORKSPACE_PREPARE_SCALE); hotseat.setScaleY(WORKSPACE_PREPARE_SCALE); } @@ -184,7 +185,7 @@ public void prepareForAtomicAnimation(LauncherState fromState, LauncherState toS config.setInterpolator(ANIM_OVERVIEW_FADE, OVERSHOOT_1_2); // Scale up the recents, if it is not coming from the side - if (overview.getVisibility() != VISIBLE || overview.getContentAlpha() == 0) { + if (overview != null && overview.getVisibility() != VISIBLE || overview.getContentAlpha() == 0) { RECENTS_SCALE_PROPERTY.set(overview, RECENTS_PREPARE_SCALE); } } From aa6547c739a962c3e36bf9126b51f245614123a2 Mon Sep 17 00:00:00 2001 From: Dhina17 Date: Fri, 5 Apr 2024 08:05:11 +0000 Subject: [PATCH 07/19] DerpLauncher: Don't create work space for parallel users Parallel users also have badge so don't consider it as work profile. Change-Id: I8b08f800b0178d3b4b09f2ab72d9de8b35cf1d64 --- .../com/android/launcher3/uioverrides/ApiWrapper.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java index 0efa0261f48..9934d3d4801 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java +++ b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java @@ -71,7 +71,9 @@ public static Map queryAllUsers(Context context) { UserManager um = context.getSystemService(UserManager.class); Map users = new ArrayMap<>(); List usersActual = um.getUserProfiles(); - usersActual.addAll(ParallelSpaceManager.getInstance().getParallelUserHandles()); + List parallelUsers = + ParallelSpaceManager.getInstance().getParallelUserHandles(); + usersActual.addAll(parallelUsers); if (usersActual != null) { for (UserHandle user : usersActual) { if (android.os.Flags.allowPrivateProfile() && Flags.enablePrivateSpace()) { @@ -93,7 +95,10 @@ public static Map queryAllUsers(Context context) { // Simple check to check if the provided user is work profile // TODO: Migrate to a better platform API NoopDrawable d = new NoopDrawable(); - boolean isWork = (d != context.getPackageManager().getUserBadgedIcon(d, user)); + // Parallel users also have badge so don't consider it as work profile + boolean isParallelUser = parallelUsers.contains(user); + boolean isWork = !isParallelUser && + d != context.getPackageManager().getUserBadgedIcon(d, user); UserIconInfo info = new UserIconInfo( user, isWork ? UserIconInfo.TYPE_WORK : UserIconInfo.TYPE_MAIN, From 43b0aa70e79d73faaee02aabf90d4ebb1ba64010 Mon Sep 17 00:00:00 2001 From: minaripenguin Date: Sun, 17 Sep 2023 00:09:38 +0800 Subject: [PATCH 08/19] DerpLauncher: Launch apps in freeform mode system shortcut Change-Id: I3b68d38509cbe45890bfab49435be2e08ea04e26 Signed-off-by: minaripenguin --- .../uioverrides/QuickstepLauncher.java | 2 + .../launcher3/popup/SystemShortcut.java | 40 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index fbfd7feae21..70afc1b82db 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java @@ -39,6 +39,7 @@ import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID; import static com.android.launcher3.popup.QuickstepSystemShortcut.getSplitSelectShortcutByPosition; import static com.android.launcher3.popup.SystemShortcut.APP_INFO; +import static com.android.launcher3.popup.SystemShortcut.FREE_FORM; import static com.android.launcher3.popup.SystemShortcut.INSTALL; import static com.android.launcher3.popup.SystemShortcut.WIDGETS; import static com.android.launcher3.taskbar.LauncherTaskbarUIController.ALL_APPS_PAGE_PROGRESS_INDEX; @@ -443,6 +444,7 @@ public Stream getSupportedShortcuts() { List shortcuts = new ArrayList(Arrays.asList( APP_INFO, WellbeingModel.SHORTCUT_FACTORY, mHotseatPredictionController)); shortcuts.addAll(getSplitShortcuts()); + shortcuts.add(FREE_FORM); shortcuts.add(WIDGETS); shortcuts.add(INSTALL); return shortcuts.stream(); diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java index 6528e757bf6..bd028d029cd 100644 --- a/src/com/android/launcher3/popup/SystemShortcut.java +++ b/src/com/android/launcher3/popup/SystemShortcut.java @@ -1,10 +1,14 @@ package com.android.launcher3.popup; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; + import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_WIDGETS_TAP; import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_TASK; +import android.app.Activity; +import android.app.ActivityManagerNative; import android.app.ActivityOptions; import android.content.ComponentName; import android.content.Context; @@ -16,6 +20,7 @@ import android.net.Uri; import android.util.Log; import android.view.View; +import android.view.WindowInsets; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.ImageView; import android.widget.TextView; @@ -313,6 +318,41 @@ public void onClick(View view) { } } + public static final Factory FREE_FORM = (activity, itemInfo, originalView) -> + new FreeForm(activity, itemInfo, originalView); + + public static class FreeForm extends SystemShortcut { + private final String mPackageName; + + public FreeForm(BaseDraggingActivity target, ItemInfo itemInfo, View originalView) { + super(R.drawable.ic_caption_desktop_button_foreground, R.string.recent_task_option_freeform, target, itemInfo, originalView); + mPackageName = itemInfo.getTargetComponent().getPackageName(); + } + + @Override + public void onClick(View view) { + if (mPackageName != null) { + Intent intent = mTarget.getPackageManager().getLaunchIntentForPackage(mPackageName); + if (intent != null) { + ActivityOptions options = makeLaunchOptions(mTarget); + mTarget.startActivity(intent, options.toBundle()); + AbstractFloatingView.closeAllOpenViews(mTarget); + } + } + } + + private ActivityOptions makeLaunchOptions(Activity activity) { + ActivityOptions activityOptions = ActivityOptions.makeBasic(); + activityOptions.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM); + final View decorView = activity.getWindow().getDecorView(); + final WindowInsets insets = decorView.getRootWindowInsets(); + final Rect r = new Rect(0, 0, decorView.getWidth() / 2, decorView.getHeight() / 2); + r.offsetTo(insets.getSystemWindowInsetLeft() + 50, insets.getSystemWindowInsetTop() + 50); + activityOptions.setLaunchBounds(r); + return activityOptions; + } + } + public static void dismissTaskMenuView(T activity) { AbstractFloatingView.closeOpenViews(activity, true, AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE); From 22305d02b3be1bfae45f045f5f2b5ba55a0cb4b6 Mon Sep 17 00:00:00 2001 From: minaripenguin Date: Sun, 17 Sep 2023 10:45:57 +0800 Subject: [PATCH 09/19] DerpLauncher: Hide freeform shortcut if app doesnt support freeform Change-Id: I06669608d77995c7d9f65f3b4a14872f67bea208 --- src/com/android/launcher3/popup/SystemShortcut.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java index bd028d029cd..801f76550f7 100644 --- a/src/com/android/launcher3/popup/SystemShortcut.java +++ b/src/com/android/launcher3/popup/SystemShortcut.java @@ -42,6 +42,7 @@ import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.views.ActivityContext; import com.android.launcher3.widget.WidgetsBottomSheet; +import com.android.systemui.shared.system.ActivityManagerWrapper; import java.net.URISyntaxException; import java.util.List; @@ -319,7 +320,9 @@ public void onClick(View view) { } public static final Factory FREE_FORM = (activity, itemInfo, originalView) -> - new FreeForm(activity, itemInfo, originalView); + ActivityManagerWrapper.getInstance().supportsFreeformMultiWindow(activity) + ? new FreeForm(activity, itemInfo, originalView) + : null; public static class FreeForm extends SystemShortcut { private final String mPackageName; From 57a391cc2b51d3f536e0f40cfb47846448b16deb Mon Sep 17 00:00:00 2001 From: minaripenguin Date: Sun, 17 Sep 2023 11:46:41 +0800 Subject: [PATCH 10/19] DerpLauncher: freeform: Launch tasks as tasks overlays * we want to make the activity always the top activity for the launched task. Following OEM multi-window behaviour. Change-Id: I5d03dac91ad5731065c6b44c94f7ddac585c9091 Signed-off-by: minaripenguin --- src/com/android/launcher3/popup/SystemShortcut.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java index 801f76550f7..34ec2ae506e 100644 --- a/src/com/android/launcher3/popup/SystemShortcut.java +++ b/src/com/android/launcher3/popup/SystemShortcut.java @@ -25,6 +25,7 @@ import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; +import android.window.SplashScreen; import android.os.UserHandle; import androidx.annotation.Nullable; @@ -352,6 +353,8 @@ private ActivityOptions makeLaunchOptions(Activity activity) { final Rect r = new Rect(0, 0, decorView.getWidth() / 2, decorView.getHeight() / 2); r.offsetTo(insets.getSystemWindowInsetLeft() + 50, insets.getSystemWindowInsetTop() + 50); activityOptions.setLaunchBounds(r); + activityOptions.setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_ICON); + activityOptions.setTaskOverlay(true /* taskOverlay */, true /* canResume */); return activityOptions; } } From c0409e0f1ce06d1f07507ec83fc7916bd9019553 Mon Sep 17 00:00:00 2001 From: NurKeinNeid Date: Sun, 7 Apr 2024 12:16:57 +0200 Subject: [PATCH 11/19] DerpLauncher: Bump version to AP1A.240405.002 Change-Id: Ic3ed16bb0bea98d9dd5da96da63c65ebe735047b Signed-off-by: NurKeinNeid --- res/values/derp_strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/values/derp_strings.xml b/res/values/derp_strings.xml index 49a08eeb690..d8498924858 100644 --- a/res/values/derp_strings.xml +++ b/res/values/derp_strings.xml @@ -167,7 +167,7 @@ DerpLauncher Based on AOSP Launcher3 - AP1A.240305.019 + AP1A.240405.002 Special thanks to About Info about the DerpLauncher From 70d344ff56106723474f7902e1aaec136b791b7d Mon Sep 17 00:00:00 2001 From: NurKeinNeid Date: Sun, 7 Apr 2024 15:57:16 +0200 Subject: [PATCH 12/19] Revert "DerpLauncher: Add support for toggling taskbar" This reverts commit e369fc8cfcee7881793e75acd92352561089d4a0. --- .../launcher3/taskbar/TaskbarManager.java | 6 ++-- .../com/android/quickstep/SystemUiProxy.java | 12 -------- src/com/android/launcher3/DeviceProfile.java | 6 +--- .../launcher3/InvariantDeviceProfile.java | 29 ------------------- 4 files changed, 3 insertions(+), 50 deletions(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java index 8efc7190cd8..bbac11625d5 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java @@ -428,15 +428,13 @@ public void recreateTaskbar() { destroyExistingTaskbar(); boolean isTaskbarEnabled = dp != null && isTaskbarPresent(dp); - - SystemUiProxy sysui = SystemUiProxy.INSTANCE.get(mContext); - sysui.setTaskbarEnabled(isTaskbarEnabled); debugWhyTaskbarNotDestroyed("recreateTaskbar: isTaskbarEnabled=" + isTaskbarEnabled + " [dp != null (i.e. mUserUnlocked)]=" + (dp != null) + " FLAG_HIDE_NAVBAR_WINDOW=" + ENABLE_TASKBAR_NAVBAR_UNIFICATION + " dp.isTaskbarPresent=" + (dp == null ? "null" : dp.isTaskbarPresent)); if (!isTaskbarEnabled) { - sysui.notifyTaskbarStatus(/* visible */ false, /* stashed */ false); + SystemUiProxy.INSTANCE.get(mContext) + .notifyTaskbarStatus(/* visible */ false, /* stashed */ false); return; } diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java index 613da968c46..723af434683 100644 --- a/quickstep/src/com/android/quickstep/SystemUiProxy.java +++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java @@ -475,18 +475,6 @@ public void notifyPrioritizedRotation(int rotation) { } } - @Override - public void setTaskbarEnabled(boolean enabled) { - if (mSystemUiProxy != null) { - try { - mSystemUiProxy.setTaskbarEnabled(enabled); - } catch (RemoteException e) { - Log.w(TAG, "Failed call setTaskbarEnabled with arg: " + - enabled, e); - } - } - } - @Override public void notifyTaskbarStatus(boolean visible, boolean stashed) { if (mSystemUiProxy != null) { diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index 6cddbbd9b23..a780e0927b3 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -71,8 +71,6 @@ import com.android.launcher3.util.ResourceHelper; import com.android.launcher3.util.WindowBounds; -import android.provider.Settings; - import java.io.PrintWriter; import java.util.Locale; import java.util.function.Consumer; @@ -360,9 +358,7 @@ public class DeviceProfile { isTablet = info.isTablet(windowBounds); isPhone = !isTablet; isTwoPanels = isTablet && isMultiDisplay; - boolean isTaskBarEnabled = Settings.System.getInt(context.getContentResolver(), - Settings.System.ENABLE_TASKBAR, isTablet ? 1 : 0) == 1; - isTaskbarPresent = isTaskBarEnabled && ApiWrapper.TASKBAR_DRAWN_IN_PROCESS; + isTaskbarPresent = isTablet && ApiWrapper.TASKBAR_DRAWN_IN_PROCESS; // Some more constants. context = getContext(context, info, isVerticalBarLayout() || (isTablet && isLandscape) diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java index 76e6b826146..e0819c28a46 100644 --- a/src/com/android/launcher3/InvariantDeviceProfile.java +++ b/src/com/android/launcher3/InvariantDeviceProfile.java @@ -243,31 +243,6 @@ public class InvariantDeviceProfile implements OnSharedPreferenceChangeListener private final ArrayList mChangeListeners = new ArrayList<>(); - private static final Uri ENABLE_TASKBAR_URI = Settings.System.getUriFor( - Settings.System.ENABLE_TASKBAR); - - private final class SettingsContentObserver extends ContentObserver { - SettingsContentObserver() { - super(new Handler(Looper.getMainLooper())); - } - - @Override - public void onChange(boolean selfChange, Uri uri) { - if (ENABLE_TASKBAR_URI.equals(uri)) { - // Create the illusion of this taking effect immediately - // Also needed because TaskbarManager inits before SystemUiProxy on start - boolean enabled = Settings.System.getInt(mContext.getContentResolver(), - Settings.System.ENABLE_TASKBAR, 0) == 1; - SystemUiProxy.INSTANCE.get(mContext).setTaskbarEnabled(enabled); - - // Restart launcher - System.exit(0); - } - } - } - - private final SettingsContentObserver mSettingsObserver = new SettingsContentObserver(); - @VisibleForTesting public InvariantDeviceProfile() { } @@ -293,10 +268,6 @@ private InvariantDeviceProfile(Context context) { onConfigChanged(displayContext); } }); - - final ContentResolver resolver = mContext.getContentResolver(); - resolver.registerContentObserver(ENABLE_TASKBAR_URI, false, - mSettingsObserver); } /** From 883a8544429c16a48434aeb4449a964844bc4a8b Mon Sep 17 00:00:00 2001 From: Danny Lin Date: Sun, 10 Apr 2022 18:38:45 -0700 Subject: [PATCH 13/19] DerpLauncher: Add support for toggling taskbar - Use new API to enable/disable SysUI taskbar integration - User-facing setting to control taskbar eligibility - Reload by restarting (live reload would be much more complicated) - Update SysUI integration state before reloading Depends on frameworks/base commit: SystemUI: Add API for runtime taskbar config Change-Id: Id1889ca9b102f94cc0a1161f49de88428dcc0943 Signed-off-by: Mohammad Hasan Keramat J Signed-off-by: SahilSonar --- .../launcher3/taskbar/TaskbarManager.java | 23 +++++++++++++++++-- .../com/android/quickstep/SystemUiProxy.java | 12 ++++++++++ src/com/android/launcher3/DeviceProfile.java | 6 ++++- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java index bbac11625d5..af1cfde54a9 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java @@ -73,6 +73,8 @@ import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider; import com.android.wm.shell.Flags; +import android.provider.Settings; + import java.io.PrintWriter; import java.util.StringJoiner; @@ -105,6 +107,9 @@ public class TaskbarManager { private static final Uri NAV_BAR_KIDS_MODE = Settings.Secure.getUriFor( Settings.Secure.NAV_BAR_KIDS_MODE); + private static final Uri ENABLE_TASKBAR_URI = Settings.System.getUriFor( + Settings.System.ENABLE_TASKBAR); + private final Context mContext; private final @Nullable Context mNavigationBarPanelContext; private WindowManager mWindowManager; @@ -137,6 +142,7 @@ public class TaskbarManager { */ private final OnIDPChangeListener mIdpChangeListener = c -> recreateTaskbar(); private final SettingsCache.OnChangeListener mOnSettingsChangeListener = c -> recreateTaskbar(); + private final SettingsCache.OnChangeListener mEnableTaskBarListener; private boolean mUserUnlocked = false; @@ -276,6 +282,18 @@ public void onLowMemory() { } SettingsCache.INSTANCE.get(mContext) .register(NAV_BAR_KIDS_MODE, mOnSettingsChangeListener); Log.d(TASKBAR_NOT_DESTROYED_TAG, "registering component callbacks from constructor."); + mEnableTaskBarListener = c -> { + // Create the illusion of this taking effect immediately + // Also needed because TaskbarManager inits before SystemUiProxy on start + boolean enabled = Settings.System.getInt(mContext.getContentResolver(), + Settings.System.ENABLE_TASKBAR, 0) == 1; + SystemUiProxy.INSTANCE.get(mContext).setTaskbarEnabled(enabled); + + // Restart launcher + System.exit(0); + }; + SettingsCache.INSTANCE.get(mContext) + .register(ENABLE_TASKBAR_URI, mEnableTaskBarListener); mContext.registerComponentCallbacks(mComponentCallbacks); mShutdownReceiver.register(mContext, Intent.ACTION_SHUTDOWN); UI_HELPER_EXECUTOR.execute(() -> { @@ -432,9 +450,10 @@ public void recreateTaskbar() { + " [dp != null (i.e. mUserUnlocked)]=" + (dp != null) + " FLAG_HIDE_NAVBAR_WINDOW=" + ENABLE_TASKBAR_NAVBAR_UNIFICATION + " dp.isTaskbarPresent=" + (dp == null ? "null" : dp.isTaskbarPresent)); + SystemUiProxy sysui = SystemUiProxy.INSTANCE.get(mContext); + sysui.setTaskbarEnabled(isTaskbarEnabled); if (!isTaskbarEnabled) { - SystemUiProxy.INSTANCE.get(mContext) - .notifyTaskbarStatus(/* visible */ false, /* stashed */ false); + sysui.notifyTaskbarStatus(/* visible */ false, /* stashed */ false); return; } diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java index 723af434683..613da968c46 100644 --- a/quickstep/src/com/android/quickstep/SystemUiProxy.java +++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java @@ -475,6 +475,18 @@ public void notifyPrioritizedRotation(int rotation) { } } + @Override + public void setTaskbarEnabled(boolean enabled) { + if (mSystemUiProxy != null) { + try { + mSystemUiProxy.setTaskbarEnabled(enabled); + } catch (RemoteException e) { + Log.w(TAG, "Failed call setTaskbarEnabled with arg: " + + enabled, e); + } + } + } + @Override public void notifyTaskbarStatus(boolean visible, boolean stashed) { if (mSystemUiProxy != null) { diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index a780e0927b3..6cddbbd9b23 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -71,6 +71,8 @@ import com.android.launcher3.util.ResourceHelper; import com.android.launcher3.util.WindowBounds; +import android.provider.Settings; + import java.io.PrintWriter; import java.util.Locale; import java.util.function.Consumer; @@ -358,7 +360,9 @@ public class DeviceProfile { isTablet = info.isTablet(windowBounds); isPhone = !isTablet; isTwoPanels = isTablet && isMultiDisplay; - isTaskbarPresent = isTablet && ApiWrapper.TASKBAR_DRAWN_IN_PROCESS; + boolean isTaskBarEnabled = Settings.System.getInt(context.getContentResolver(), + Settings.System.ENABLE_TASKBAR, isTablet ? 1 : 0) == 1; + isTaskbarPresent = isTaskBarEnabled && ApiWrapper.TASKBAR_DRAWN_IN_PROCESS; // Some more constants. context = getContext(context, info, isVerticalBarLayout() || (isTablet && isLandscape) From 7752f2fad94fd4b6b914dd22bb9f8fa26671a44d Mon Sep 17 00:00:00 2001 From: NurKeinNeid Date: Mon, 8 Apr 2024 01:32:37 +0200 Subject: [PATCH 14/19] DerpLauncher: Derp more quickspace strings Change-Id: If7c834ba2bb972b2867939a1f47468a0f1ff6e12 Signed-off-by: NurKeinNeid --- res/values/derp_strings.xml | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/res/values/derp_strings.xml b/res/values/derp_strings.xml index d8498924858..3c23fd96dba 100644 --- a/res/values/derp_strings.xml +++ b/res/values/derp_strings.xml @@ -205,11 +205,12 @@ DerpFest time! Thank you for choosing us - Loving us? Send us a beer Best Rom Ever. Say hi to us on Telegram Tap here to begin We love you 3000 + DerpFest FTW! + #StayDerped @@ -341,7 +342,6 @@ Your attitude determines your direction. - Ignorance is Bliss Is it time to flash another update already? Make peace, not war Oh hey, what\'s up? @@ -354,7 +354,6 @@ \u003C\u003C\u003C\u003C\u003C\u003C\u003C HEAD You need DerpFest Premium to see this Remember the Lineage of the Unicorn - Enjoy Xtended battery life Starting from the ground zero We love you 3000 Delicious even without Sushi @@ -362,7 +361,7 @@ This is best Pixel Experience, isn\'t it? No illusions, welcome to reality! Thank you for your support - No festival for Derps - only perfection! + Is your device derped? One of the buildbot\'s best picks Sanity for your Paranoia Try Ice Cold desserts @@ -379,6 +378,22 @@ Check your email/messages. Check your to-do list if you have one. You can disable quickspace via home settings. + #StayDerped \m/ + DerpFest FTW \m/ + Enjoying Android 14? + Hyped about Android 15? + Proudly presented without donations + Did you checkout all the tweaks? + You have tapped almost a 100k times. + Lots of options! + I am not your F1 button + Don\'t pass me! + Did you finish your homework? ツ + This is best ROM Experience, isn\'t it? + Well done! You have earned a bonus feature + That\'s enough, stop tapping me! + Only for pro users + Got an issue? Don\'t forget a logcat From 289e66d4a3f09d8cfe671192f29b7cfe3d8566ee Mon Sep 17 00:00:00 2001 From: NurKeinNeid Date: Tue, 9 Apr 2024 00:32:27 +0200 Subject: [PATCH 15/19] DerpLauncher: Set about app version to untranslatable Change-Id: Ifa7a6d8386c8adcadb81cb762758b06a8164f811 Signed-off-by: NurKeinNeid --- res/values-de/derp_strings.xml | 1 - res/values/derp_strings.xml | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/res/values-de/derp_strings.xml b/res/values-de/derp_strings.xml index 80c20f2e1cc..588d68fbed1 100644 --- a/res/values-de/derp_strings.xml +++ b/res/values-de/derp_strings.xml @@ -155,7 +155,6 @@ Basierend auf AOSP Launcher3 - AP1A.240305.019 Besonderen Dank an Über Info über den DerpLauncher diff --git a/res/values/derp_strings.xml b/res/values/derp_strings.xml index 3c23fd96dba..b39e3593b8f 100644 --- a/res/values/derp_strings.xml +++ b/res/values/derp_strings.xml @@ -167,7 +167,7 @@ DerpLauncher Based on AOSP Launcher3 - AP1A.240405.002 + AP1A.240405.002 Special thanks to About Info about the DerpLauncher From 876e7a1c2dbbcf1071cf4b0f03e31c797810ac25 Mon Sep 17 00:00:00 2001 From: Mohammad Hasan Keramat J Date: Tue, 9 Apr 2024 09:39:29 +0000 Subject: [PATCH 16/19] DerpLauncher: Fix spit drawable gravity in recents Change-Id: I9829956c22037e725f9b4facfc6eedab269b75d5 Signed-off-by: Mohammad Hasan Keramat J --- .../src/com/android/quickstep/views/OverviewActionsView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java index 1220adb2b61..e95ff0e5dfe 100644 --- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java +++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java @@ -411,7 +411,7 @@ public void updateDimension(DeviceProfile dp, Rect taskSize) { Drawable splitbutton = ContextCompat.getDrawable(getContext(), (dp.isLeftRightSplit ? R.drawable.ic_split_horizontal : R.drawable.ic_split_vertical)); mSplitButton.setForeground(splitbutton); - mSplitButton.setForegroundGravity(Gravity.CENTER); + mSplitButton.setForegroundGravity(Gravity.RIGHT); return; } From 9c2073083912c921b7a783304f69438c9b1cdc48 Mon Sep 17 00:00:00 2001 From: Mohammad Hasan Keramat J Date: Tue, 9 Apr 2024 10:45:51 +0000 Subject: [PATCH 17/19] fixup! DerpLauncher: allow disabling overview action chips Signed-off-by: Mohammad Hasan Keramat J Change-Id: I4eb03d566e26eadb158a9bf3203dce43d3ae8d76 --- .../src/com/android/quickstep/views/OverviewActionsView.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java index e95ff0e5dfe..d3b43d44050 100644 --- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java +++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java @@ -203,7 +203,7 @@ private void updateVisibilities() { lens.setVisibility(mLens && Utilities.isGSAEnabled(getContext()) ? VISIBLE : GONE); findViewById(R.id.lens_space).setVisibility(mLens && Utilities.isGSAEnabled(getContext()) ? VISIBLE : GONE); - mSplitButton = findViewById(R.id.action_split); + mSplitButton = findViewById(mUseChips ? R.id.action2_split : R.id.action_split); mSplitButton.setOnClickListener(this); } @@ -411,7 +411,7 @@ public void updateDimension(DeviceProfile dp, Rect taskSize) { Drawable splitbutton = ContextCompat.getDrawable(getContext(), (dp.isLeftRightSplit ? R.drawable.ic_split_horizontal : R.drawable.ic_split_vertical)); mSplitButton.setForeground(splitbutton); - mSplitButton.setForegroundGravity(Gravity.RIGHT); + mSplitButton.setForegroundGravity(Gravity.CENTER); return; } From e32f7af3bebf61b8e09f128d85e4714c32e3e6e0 Mon Sep 17 00:00:00 2001 From: Mohammad Hasan Keramat J Date: Tue, 9 Apr 2024 11:21:54 +0000 Subject: [PATCH 18/19] DerpLauncher: Restart on disabling overview action chips Change-Id: I045313b1828b8967701e87f9bbadb99d9e9aad50 Signed-off-by: Mohammad Hasan Keramat J --- src/com/android/launcher3/Utilities.java | 1 + .../android/launcher3/settings/SettingsRecents.java | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index 2dee56b79c2..e65efac70d9 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -200,6 +200,7 @@ public final class Utilities { public static final String KEY_LENS = "pref_recents_lens"; public static final String KEY_SHORT_PARALLAX = "pref_short_parallax"; public static final String KEY_SINGLE_PAGE_CENTER = "pref_single_page_center"; + public static final String KEY_RECENTS_CHIPS = "pref_recents_chips"; public static final String DESKTOP_SHOW_QUICKSPACE = "pref_show_quickspace"; public static final String KEY_SHOW_ALT_QUICKSPACE = "pref_show_alt_quickspace"; public static final String KEY_SHOW_QUICKSPACE_PSONALITY = "pref_quickspace_psonality"; diff --git a/src/com/android/launcher3/settings/SettingsRecents.java b/src/com/android/launcher3/settings/SettingsRecents.java index aca62037006..07fc11fb7d7 100644 --- a/src/com/android/launcher3/settings/SettingsRecents.java +++ b/src/com/android/launcher3/settings/SettingsRecents.java @@ -100,7 +100,15 @@ protected void onCreate(Bundle savedInstanceState) { } @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { } + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + switch (key) { + case Utilities.KEY_RECENTS_CHIPS: + LauncherAppState.getInstanceNoCreate().setNeedsRestart(); + break; + default: + break; + } + } private boolean startPreference(String fragment, Bundle args, String key) { if (Utilities.ATLEAST_P && getSupportFragmentManager().isStateSaved()) { From 020243b6d19138395b92d6cf0deb3a7029e8bdb5 Mon Sep 17 00:00:00 2001 From: DenlNister <41001774+nnn950711@users.noreply.github.com> Date: Thu, 11 Apr 2024 23:00:09 +0800 Subject: [PATCH 19/19] DerpLauncher: Add zh-rTW translations --- res/values-zh-rTW/derp_strings.xml | 408 +++++++++++++++++++++++++++++ 1 file changed, 408 insertions(+) create mode 100644 res/values-zh-rTW/derp_strings.xml diff --git a/res/values-zh-rTW/derp_strings.xml b/res/values-zh-rTW/derp_strings.xml new file mode 100644 index 00000000000..488ae47389d --- /dev/null +++ b/res/values-zh-rTW/derp_strings.xml @@ -0,0 +1,408 @@ + + + + + + 主畫面設定 + + + 主畫面 + Set home panel and more + 圖示 + Set icon size and more + 應用程式抽屜 + 自訂你的應用程式抽屜 + Recents + Revamp the overview screen + 雜項 + 其他選項 + 一般 + Interface + 資訊一覽 + 搜尋列 + 快速操作 + + + 開發人員選項 + Enable some hidden features at your own risk + + + 鎖定佈局 + 禁止在桌面上新增、移除或移動圖示和小工具 + 允許在桌面上新增、移除或移動圖示和小工 + 無法將小工具新增至主畫面 + + + 桌面標籤 + 在桌面上顯示圖示名稱 + 應用程式抽屜標籤 + 在應用程式抽屜上顯示圖示名稱 + + + Swipe to access Google app + + When you swipe right from main home screen + + When you swipe left from main home screen + + + 輕觸兩下即可休眠 + 在空白處點兩下即可關閉螢幕 + + + 值:%s + 預設 + 預設值:%s\n長按即可設定 + 已設定為預設值 + + + 圖示大小 + + + 字體大小 + + + Max lines for app label + + + 搜尋 + 智慧鏡頭 + 語音搜尋 + Google 搜尋列 + 在底部顯示搜尋列 + + + 底欄背景 + 在應用程式底欄上添加透明背景 + + + 桌布滑動 + Wallpaper scrolling effect for multiple screens + + + 桌布縮放 + Zoom in or out the wallpaper when using drawer or recent apps + + + 顯示狀態列 + 在主畫面上顯示狀態列 + + + 顯示頂部陰影 + 在狀態列下方添加陰影 + + + 列高 + + + 背景模糊度 + 設定最近應用程式和應用程式抽屜的背景模糊度 + + + 建議 + 在應用程式抽屜 & 主畫面上顯示建議 + + + 背景不透明度 + + + 使用緊湊設計的操作按鈕圖示 + 在顯示較多操作按鈕時可能需要 + 螢幕截圖 + 全部清除 + 智慧鏡頭 + + + 來源 + 未知 + 上次更新 + 版本 + 更多 + + + 強制關閉 + 應用程式已強制關閉 + + + %1$s 可用 | %2$s + 記憶體資訊 + + + 應用程式搜尋欄 + Search bar on top of the app drawer + + + 重新啟動 + Restart the DerpLauncher manually to apply any pending settings + 正在重新啟動 DerpLauncher... + Restarting DerpLauncher to apply changes... + Restarting DerpLauncher to update components... + + + Shake phone to clear all tasks + + + Allow short parallax + Enable full wallpaper scroll effect on smaller numbers of pages instead of cropping the wallpaper + Single page center + Center wallpaper if only using a single page + + + 圖示包 + 預設 + 安裝更多 + 沒有可用的應用程式商店 + + + 基於 AOSP Launcher3 + 特別感謝 + 關於 + 關於 DerpLauncher 的資訊 + + + 隱藏 & 受保護的應用程式 + 解鎖後即可管理隱藏和受保護的應用程式 + 進行身份驗證後即可開啟 %1$s + 載入中\u2026 + Please set up a secure lock screen to restrict app access + 說明 + Hidden apps and their widgets are hidden from the drawer + Protected apps require authentication to be opened from the launcher + + + 主題圖示 + Follow themed icons used on home screen + + + 深色狀態列 + 在主畫面上使用深色狀態列 + + + 強制使用單色圖示 + Force monochrome icons for apps that don\'t support them natively (requires re-toggling of themed icons) + + + 快速查看 + 在主畫面頂部上顯示 + + + 歡迎來到 DerpFest! + DerpFest 時間! + + 感謝你選擇我們 + 有史以來最好的 ROM + 來我們的 Telegram 群組上 Say hi 吧! + 輕觸此處開始 + 我們愛你 3000 次 + DerpFest 萬歲! + #StayDerped + + + + 早安 + 晚安 + 午安 + 晚安 + 你好 + 今天是 + 現在是 + + + 未知藝術家 + 正在播放 + 作者 + + + 正在播放 + Show the song you\'re playing + + + Extended style + Switch to extended style + + + 隨機訊息 + Make your companion more lively with random messages + + + Good morning! + Good morning, time to rock! + What a beautiful day! + Have a nice day! + What about a small 5 minutes nap? + Let\'s get this bread. + Mornings are a fresh canvas for your daily masterpiece. + Embrace the sunrise of opportunity each morning. + In the early light, find the power to illuminate your path. + Your day begins with endless possibilities. + Every sunrise is a reminder that you can start anew. + Awake with purpose, conquer the day ahead. + Your thoughts can be the foundation of great achievements. + The world awakens, and so does your potential. + The first chapter in your daily adventure. + Let your morning routine be the launchpad for success. + Sunrise or not, your potential is always on the rise. + It\'s time for fresh ideas and bold actions. + The early bird catches the worm, but you can catch your dreams. + Find the courage to chase your aspirations. + Rise and shine, for greatness awaits. + The best time to start is now. + + + Chase your dreams, not your fears. + In every moment, a new opportunity appears. + Embrace the journey, not just the destination. + Today is a gift, that\'s why it\'s called the present. + Let your smile change the world. + Life is a story, make each chapter count. + Find joy in every moments. + The best is yet to come, keep it up. + Your chance to turn \'what if\' into \'how about that\' + Seize the day, starting right now. + Happiness is a choice you can make any time. + Believe in yourself, even on a sleepy afternoon. + Let your actions speak louder than the clock. + Your life is yours, not your parents nor your friends. + Dream big, work hard, and never give up. + You are stronger than you think. + Every failure means a step closer to your success. + Your potential is endless, unlock it. + + + Embrace the present moment, no matter the hour. + In every dusk, find a new dawn of opportunity. + Life is a journey, enjoy the scenery along the way. + Your attitude shapes your reality. + Your story is still being written, even as the sun sets. + Capture the beauty in the ordinary moments. + It\'s time to reflect and reset. + Choose joy, no matter the time on the clock. + Opportunities don\'t clock out in the evening. + Be the reason someone smiles. + Your potential knows no bounds. + Moments of magic can happen at any hour. + Your life is what you make of it, make it extraordinary. + Stay curious, stay grateful. + Be the change you wish to see in the world. + Believe in yourself, you are capable of amazing things. + The only limit is the one you set for yourself. + Success begins with a single step. + + + Seize the night, for it holds its own mysteries. + In the quiet of the this evening, find serenity. + Life\'s greatest adventures can start in the darkness. + Your journey continues even after the sun has set. + Let the night be your canvas, paint it with dreams. + In the stillness of this evening, find your inner peace. + Stars shine brightest in the darkest hours. + Dream big, even in the late hours of the day. + Your life is a story waiting to be written. + It\'s time for reflection and renewal. + Late night thoughts can lead to early morning revelations. + Find joy in the stillness of this evening. + The night sky is a vast canvas of dreams. + Your potential knows no bedtime, pursue your passions. + Stay hopeful, even in the darkest hours. + In the midst of chaos, find your inner calm. + Stay positive, work hard, make it happen. + + + Nights are the quiet whispers of opportunity. + In the stillness of the night, find your inner strength. + Embrace the darkness, for it holds the keys to your dreams. + The world sleeps, but your potential is wide awake. + The night may be late, but your ambitions are timeless. + Stay curious, stay awake, and let nights guide you. + Find the courage to chase your dreams. + Great things never come from comfort zones. + You have the power to create your own destiny. + Happiness is a choice, choose it every day. + Life is what you make it, so make it count. + Stay focused, stay determined, stay unstoppable. + You are the author of your own story. + Strive for progress, not perfection. + Every day is a new beginning, make it a great one. + Inspire others by being your authentic self. + Your attitude determines your direction. + + + Is it time to flash another update already? + Make peace, not war + Oh hey, what\'s up? + Focus on your tasks + How many screenshots do you take? + Open goodness with DerpFest + Spread love, not havoc + We didn\'t start the fire! + Time for some good music + \u003C\u003C\u003C\u003C\u003C\u003C\u003C HEAD + You need DerpFest Premium to see this + Remember the Lineage of the Unicorn + Starting from the ground zero + We love you 3000 + Delicious even without Sushi + Do something nice today + This is best Pixel Experience, isn\'t it? + No illusions, welcome to reality! + Thank you for your support + Is your device derped? + One of the buildbot\'s best picks + Sanity for your Paranoia + Try Ice Cold desserts + What a lovely experience, isn\'t it? + DerpFest is a myth, right? + You are what you flash, don\'t be Potato + What\'s on your mind? + Expecto Patronum + Wubba Lubba Dub Dub + Winner Winner ....? + rm -rf \/ + Pringles aren\'t actually potato chips.. + Remember to check device\'s battery level! + Check your email/messages. + Check your to-do list if you have one. + You can disable quickspace via home settings. + #StayDerped \m/ + DerpFest FTW \m/ + Enjoying Android 14? + Hyped about Android 15? + Proudly presented without donations + Did you checkout all the tweaks? + You have tapped almost a 100k times. + Lots of options! + I am not your F1 button + Don\'t pass me! + Did you finish your homework? ツ + This is best ROM Experience, isn\'t it? + Well done! You have earned a bonus feature + That\'s enough, stop tapping me! + Only for pro users + Got an issue? Don\'t forget a logcat + + + + 天氣更新 + 顯示目前的天氣更新 + 需要啟用天氣服務 + Cloudy + Rainy + Sunny + Stormy + Snowy + Windy + Misty + 目前位置 + 顯示目前天氣位置 + Current condition + Display current weather condition summary + + Unable to find calendar or clock activity + + + 天氣設定 + 設定圖示包和天氣服務 +