From 97cdcc9f30586a101d85bdd135e7fe4e3a51d366 Mon Sep 17 00:00:00 2001 From: Danny Lin Date: Sun, 10 Apr 2022 18:38:45 -0700 Subject: [PATCH 001/164] 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 --- .../launcher3/taskbar/TaskbarManager.java | 21 +++++++++++++++++-- .../com/android/quickstep/SystemUiProxy.java | 12 +++++++++++ src/com/android/launcher3/DeviceProfile.java | 6 +++++- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java index 2a58db25dfc..65a010bad17 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java @@ -109,6 +109,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; @@ -151,6 +154,7 @@ public void onDisplayInfoChanged(Context context, DisplayController.Info info, i } } private final SettingsCache.OnChangeListener mOnSettingsChangeListener = c -> recreateTaskbar(); + private final SettingsCache.OnChangeListener mEnableTaskBarListener; private boolean mUserUnlocked = false; @@ -302,6 +306,18 @@ public void onLowMemory() { } .register(USER_SETUP_COMPLETE_URI, mOnSettingsChangeListener); SettingsCache.INSTANCE.get(mContext) .register(NAV_BAR_KIDS_MODE, mOnSettingsChangeListener); + 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); Log.d(TASKBAR_NOT_DESTROYED_TAG, "registering component callbacks from constructor."); mContext.registerComponentCallbacks(mComponentCallbacks); mShutdownReceiver.register(mContext, Intent.ACTION_SHUTDOWN); @@ -458,9 +474,10 @@ public synchronized 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 433baa95811..a741f1284a9 100644 --- a/quickstep/src/com/android/quickstep/SystemUiProxy.java +++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java @@ -518,6 +518,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 00db3a38860..20ad72d2a2c 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -42,6 +42,7 @@ import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; +import android.provider.Settings; import android.util.DisplayMetrics; import android.util.SparseArray; import android.view.Surface; @@ -353,7 +354,10 @@ public class DeviceProfile { isTablet = info.isTablet(windowBounds); isPhone = !isTablet; isTwoPanels = isTablet && isMultiDisplay; - isTaskbarPresent = (isTablet || (enableTinyTaskbar() && isGestureMode)) + boolean isTaskBarEnabled = Settings.System.getInt(context.getContentResolver(), + Settings.System.ENABLE_TASKBAR, (isTablet || (enableTinyTaskbar() + && isGestureMode)) ? 1 : 0) == 1; + isTaskbarPresent = isTaskBarEnabled && WindowManagerProxy.INSTANCE.get(context).isTaskbarDrawnInProcess(); // Some more constants. From a78353a2ba2f37f3183c9123dec75d3d07e47841 Mon Sep 17 00:00:00 2001 From: Ali B Date: Tue, 18 Jan 2022 16:35:28 +0300 Subject: [PATCH 002/164] DerpLauncher: Fix NPE with swipe down Depending on the navigation mode in use, the animation used for the swipe down gesture may result in a NPE. While it works perfectly fine with full gesture or 2-button navigation modes, an NPE results when swiped down on 3-button navitation as recents task is trigged with the third button instead of the swipe up gesture. Change-Id: Id276489a8d2acdd44d4e33fcc1bc6a9b193e0bf8 --- .../touchcontrollers/TaskViewTouchController.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java index 4bc3c1661ed..2aa9989d2ab 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java @@ -327,8 +327,10 @@ public boolean onDrag(float displacement) { mDraggingEnabled = false; } } else { - mCurrentAnimation.setPlayFraction( - Utilities.boundToRange(totalDisplacement * mProgressMultiplier, 0, 1)); + if (mCurrentAnimation != null) { + mCurrentAnimation.setPlayFraction( + Utilities.boundToRange(totalDisplacement * mProgressMultiplier, 0, 1)); + } } return true; From 69174725636363a95c3bff1c5c5e9aaf22da00d6 Mon Sep 17 00:00:00 2001 From: Danny Lin Date: Sun, 10 Oct 2021 03:40:52 -0700 Subject: [PATCH 003/164] DerpLauncher: Improve search bar UI in All Apps This is similar to, but not exactly the same as, Pixel stock: - Background color with contrast in light mode - Round, flat search bar surface with color matching the header background - Solid rounded background when positioned at the beginning of the list - Subtle placeholder text (medium weight) without icon - Same font size as Settings search bar Change-Id: Ifa9fabe3a8236513fad8030c0bd8ed4d27ebd549 --- res/drawable/all_apps_search_hint.xml | 2 +- res/drawable/bg_all_apps_searchbox.xml | 3 +-- res/layout/search_container_all_apps.xml | 4 ++-- res/values-v31/colors.xml | 2 +- .../launcher3/allapps/ActivityAllAppsContainerView.java | 1 + .../launcher3/allapps/search/AppsSearchContainerLayout.java | 1 - 6 files changed, 6 insertions(+), 7 deletions(-) diff --git a/res/drawable/all_apps_search_hint.xml b/res/drawable/all_apps_search_hint.xml index b2ff7a428e6..a066e98d9de 100644 --- a/res/drawable/all_apps_search_hint.xml +++ b/res/drawable/all_apps_search_hint.xml @@ -16,5 +16,5 @@ --> - + \ No newline at end of file diff --git a/res/drawable/bg_all_apps_searchbox.xml b/res/drawable/bg_all_apps_searchbox.xml index 3c321e4c499..b95e468c187 100644 --- a/res/drawable/bg_all_apps_searchbox.xml +++ b/res/drawable/bg_all_apps_searchbox.xml @@ -14,7 +14,6 @@ limitations under the License. --> - + - \ No newline at end of file diff --git a/res/layout/search_container_all_apps.xml b/res/layout/search_container_all_apps.xml index db218c3d4b0..0ad13d538bf 100644 --- a/res/layout/search_container_all_apps.xml +++ b/res/layout/search_container_all_apps.xml @@ -22,16 +22,16 @@ android:layout_gravity="top|center_horizontal" android:background="@drawable/bg_all_apps_searchbox" android:focusableInTouchMode="true" - android:gravity="center" android:hint="@string/all_apps_search_bar_hint" android:imeOptions="actionSearch|flagNoExtractUi" android:importantForAutofill="no" android:inputType="text|textNoSuggestions|textCapWords" android:maxLines="1" android:padding="8dp" + android:paddingStart="16dp" android:saveEnabled="false" android:scrollHorizontally="true" android:singleLine="true" android:textColor="?android:attr/textColorSecondary" android:textColorHint="@drawable/all_apps_search_hint" - android:textSize="16sp" /> \ No newline at end of file + android:textSize="20sp" /> diff --git a/res/values-v31/colors.xml b/res/values-v31/colors.xml index fa87221f52d..ff1dfb1c7bd 100644 --- a/res/values-v31/colors.xml +++ b/res/values-v31/colors.xml @@ -19,7 +19,7 @@ @android:color/system_accent2_50 @android:color/system_neutral2_100 - @android:color/system_neutral2_300 + @android:color/system_neutral2_100 @android:color/system_neutral1_900 @android:color/system_neutral1_1000 @android:color/system_neutral2_800 diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java index 56a7fef5261..b20b00c5939 100644 --- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java @@ -776,6 +776,7 @@ protected void updateHeaderScroll(int scrolledOffset) { mTabsProtectionAlpha = tabsAlpha; invalidateHeader(); } + getSearchView().setBackgroundResource(R.drawable.bg_all_apps_searchbox); if (mSearchUiManager.getEditText() == null) { return; } diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java index 78c305b2ebd..d83efd6c16f 100644 --- a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java +++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java @@ -77,7 +77,6 @@ public AppsSearchContainerLayout(Context context, AttributeSet attrs, int defSty mSearchQueryBuilder = new SpannableStringBuilder(); Selection.setSelection(mSearchQueryBuilder, 0); - setHint(prefixTextWithIcon(getContext(), R.drawable.ic_allapps_search, getHint())); mContentOverlap = getResources().getDimensionPixelSize(R.dimen.all_apps_search_bar_content_overlap); From 6ec7a47b4e2d23a779a95d49627e62038e9fce44 Mon Sep 17 00:00:00 2001 From: Michael Bestas Date: Wed, 19 Jan 2022 23:24:39 +0200 Subject: [PATCH 004/164] DerpLauncher: Fix search bar UI in All Apps Commit Ifa9fabe3a8236513fad8030c0bd8ed4d27ebd549 improved the look of the search bar, however it had a few issues and the overall look did not match Settings or Widget search style. The following improvements have been made: - Centered the search bar text vertically inside the search bar - Fixed poor contrast of the search bar text against the background - Added back search icon that is always shown, matching Widget search - Changed paddings to match Widget search Change-Id: Ia127da05adff45f8860f0870817aaa9fde8e171c --- res/drawable/all_apps_search_hint.xml | 20 -------------------- res/drawable/ic_allapps_search.xml | 2 +- res/layout/search_container_all_apps.xml | 16 ++++++++++------ res/values/attrs.xml | 1 + res/values/styles.xml | 2 ++ 5 files changed, 14 insertions(+), 27 deletions(-) delete mode 100644 res/drawable/all_apps_search_hint.xml diff --git a/res/drawable/all_apps_search_hint.xml b/res/drawable/all_apps_search_hint.xml deleted file mode 100644 index a066e98d9de..00000000000 --- a/res/drawable/all_apps_search_hint.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/res/drawable/ic_allapps_search.xml b/res/drawable/ic_allapps_search.xml index 53b4f91d223..e7520196144 100644 --- a/res/drawable/ic_allapps_search.xml +++ b/res/drawable/ic_allapps_search.xml @@ -19,7 +19,7 @@ android:viewportHeight="24.0" android:viewportWidth="24.0" android:autoMirrored="true" - android:tint="?attr/widgetPickerSearchTextColor"> + android:tint="?attr/allAppsSearchTextColor"> diff --git a/res/layout/search_container_all_apps.xml b/res/layout/search_container_all_apps.xml index 0ad13d538bf..56d8ebb7a2b 100644 --- a/res/layout/search_container_all_apps.xml +++ b/res/layout/search_container_all_apps.xml @@ -17,21 +17,25 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:id="@id/search_container_all_apps" android:layout_width="match_parent" - android:layout_height="@dimen/all_apps_search_bar_field_height" + android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_gravity="top|center_horizontal" android:background="@drawable/bg_all_apps_searchbox" android:focusableInTouchMode="true" + android:gravity="center_vertical" android:hint="@string/all_apps_search_bar_hint" android:imeOptions="actionSearch|flagNoExtractUi" android:importantForAutofill="no" android:inputType="text|textNoSuggestions|textCapWords" android:maxLines="1" - android:padding="8dp" - android:paddingStart="16dp" + android:paddingVertical="12dp" + android:paddingStart="12dp" + android:paddingEnd="0dp" + android:drawablePadding="8dp" + android:drawableStart="@drawable/ic_allapps_search" android:saveEnabled="false" android:scrollHorizontally="true" android:singleLine="true" - android:textColor="?android:attr/textColorSecondary" - android:textColorHint="@drawable/all_apps_search_hint" - android:textSize="20sp" /> + android:textColor="?android:attr/textColorPrimary" + android:textColorHint="?attr/allAppsSearchTextColor" + android:textSize="20sp" /> \ No newline at end of file diff --git a/res/values/attrs.xml b/res/values/attrs.xml index be8b2e13d9a..3483ab8cf28 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -21,6 +21,7 @@ + diff --git a/res/values/styles.xml b/res/values/styles.xml index ae3d3b3e111..c4f2c85fe11 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -35,6 +35,7 @@ @color/material_color_surface_container_highest #66FFFFFF + @color/widget_picker_search_text_color_light @color/popup_color_primary_light @color/popup_color_secondary_light @color/popup_color_tertiary_light @@ -155,6 +156,7 @@ ?attr/materialColorSurfaceDim @color/material_color_surface_container_low #80000000 + @color/widget_picker_search_text_color_dark @color/popup_color_primary_dark @color/popup_color_secondary_dark @color/popup_color_tertiary_dark From 220ffc35e78c9ae37025893cdcf55c5bcac517fd Mon Sep 17 00:00:00 2001 From: Michael Bestas Date: Thu, 20 Jan 2022 02:13:38 +0200 Subject: [PATCH 005/164] DerpLauncher: Update search icon to match Settings Change-Id: Ic779bf0bf20046bfe92385e6a09796e94ba68644 --- res/drawable/ic_allapps_search.xml | 40 ++++++++++++++++-------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/res/drawable/ic_allapps_search.xml b/res/drawable/ic_allapps_search.xml index e7520196144..0e9f9b4e5cd 100644 --- a/res/drawable/ic_allapps_search.xml +++ b/res/drawable/ic_allapps_search.xml @@ -1,26 +1,28 @@ - - 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. ---> + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24" + android:autoMirrored="true" + android:tint="?attr/allAppsSearchTextColor"> + android:pathData="M20.49,19l-5.73,-5.73C15.53,12.2 16,10.91 16,9.5C16,5.91 13.09,3 9.5,3S3,5.91 3,9.5C3,13.09 5.91,16 9.5,16c1.41,0 2.7,-0.47 3.77,-1.24L19,20.49L20.49,19zM5,9.5C5,7.01 7.01,5 9.5,5S14,7.01 14,9.5S11.99,14 9.5,14S5,11.99 5,9.5z"/> From 363f7e36fe12a84bdb5c2ae133d5ffdafe3f96de Mon Sep 17 00:00:00 2001 From: Pranav Vashi Date: Thu, 3 Feb 2022 09:08:54 +0530 Subject: [PATCH 006/164] DerpLauncher: Increase end padding for search bar UI * Else text goes brrrr.... Signed-off-by: Pranav Vashi Change-Id: Ie7f872aaa5677ead3128ef2fbe410434d28953ef --- res/layout/search_container_all_apps.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/layout/search_container_all_apps.xml b/res/layout/search_container_all_apps.xml index 56d8ebb7a2b..a5f1a35e53c 100644 --- a/res/layout/search_container_all_apps.xml +++ b/res/layout/search_container_all_apps.xml @@ -30,7 +30,7 @@ android:maxLines="1" android:paddingVertical="12dp" android:paddingStart="12dp" - android:paddingEnd="0dp" + android:paddingEnd="12dp" android:drawablePadding="8dp" android:drawableStart="@drawable/ic_allapps_search" android:saveEnabled="false" From daf9f8b611b3a234f058da28bc31631e04c46791 Mon Sep 17 00:00:00 2001 From: Yingren Wang Date: Tue, 8 Dec 2020 12:59:43 +0800 Subject: [PATCH 007/164] DerpLauncher: Fix gesture navigation fail to move to bottom Go to the recents page from all apps page and rotate to horizontal, at last switch to one app that only support portrait display, we will see the gesture navigation always at device right and not move to bottom. At this scenario, launcher state switch from overview to all apps, but launcher not notify systemui update gesture navigation display. To slove this, launcher must notify systemui update gesture navigation display when launcher state switch from overview to all apps. CRs-Fixed: 2828560 Change-Id: Ib2319045d3851b43dadd6a0e06ac65be2e5227f7 --- .../src/com/android/quickstep/LauncherActivityInterface.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java index b564fa752a9..8309910a8b7 100644 --- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java +++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java @@ -249,7 +249,7 @@ public void onExitOverview(RotationTouchHelper deviceState, Runnable exitRunnabl @Override public void onStateTransitionComplete(LauncherState toState) { // Are we going from Recents to Workspace? - if (toState == LauncherState.NORMAL) { + if (toState == LauncherState.NORMAL || toState == LauncherState.ALL_APPS) { exitRunnable.run(); notifyRecentsOfOrientation(deviceState); stateManager.removeStateListener(this); From 1c0c6f4ab353009684cf08f5685f24b311518e34 Mon Sep 17 00:00:00 2001 From: Michael Bestas Date: Sat, 26 Nov 2022 16:39:06 +0200 Subject: [PATCH 008/164] DerpLauncher: Disable all caps from Personal and Work tabs Matches Pixel launcher look. Change-Id: I3808763c13f25c12f31d6e6f98abd29dc3422d75 --- res/layout/all_apps_personal_work_tabs.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/res/layout/all_apps_personal_work_tabs.xml b/res/layout/all_apps_personal_work_tabs.xml index e04b207a3e8..fb9b047ea62 100644 --- a/res/layout/all_apps_personal_work_tabs.xml +++ b/res/layout/all_apps_personal_work_tabs.xml @@ -36,6 +36,7 @@ android:layout_weight="1" android:background="@drawable/all_apps_tabs_background" android:text="@string/all_apps_personal_tab" + android:textAllCaps="false" android:textColor="@color/all_apps_tab_text" android:textSize="14sp" style="?android:attr/borderlessButtonStyle" /> @@ -48,6 +49,7 @@ android:layout_weight="1" android:background="@drawable/all_apps_tabs_background" android:text="@string/all_apps_work_tab" + android:textAllCaps="false" android:textColor="@color/all_apps_tab_text" android:textSize="14sp" style="?android:attr/borderlessButtonStyle" /> From 6db309c6304fe518f95b22075ad284ac08947fda Mon Sep 17 00:00:00 2001 From: Tommy Webb Date: Mon, 16 Jan 2023 13:52:41 -0500 Subject: [PATCH 009/164] DerpLauncher: Fix All Apps header protection and spacing again Redone, again. This time, many comments added. Compared to I586f7332, this primarily results in some fixes for the floating header row(s) (AiAi prediction row) if present. Change-Id: Ib0f383fb89a6847fccbcc96d13b051983d76f0c5 --- res/values/dimens.xml | 12 ++++++++-- .../allapps/ActivityAllAppsContainerView.java | 24 ++++++++++++++----- .../launcher3/allapps/FloatingHeaderView.java | 7 +++--- 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 05724e2a853..74dce62459d 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -103,7 +103,12 @@ 48dp 24dp - 30dp + + + 24dp + + + -6dp 40dp 4dp 48dp @@ -114,7 +119,10 @@ 36dp 16dp - 14dp + + + 10dp 6dp 4dp 16dp diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java index b20b00c5939..b89dd1e10c8 100644 --- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java @@ -746,13 +746,22 @@ void setupHeader() { tabsHidden); int padding = mHeader.getMaxTranslation(); - mAH.forEach(adapterHolder -> { - adapterHolder.mPadding.top = padding; + for (int i = 0; i < mAH.size(); i++) { + final AdapterHolder adapterHolder = mAH.get(i); + // Search and other adapters need to be handled a bit differently; otherwise, when + // when leaving search, the All Apps view may be noticeably shifted downward because + // its padding was unnecessarily impacted, and never restored, upon entering search. + if (i != AdapterHolder.SEARCH && !tabsHidden && mHeader.getFloatingRowsHeight() == 0) { + // Only the Search adapter needs padding when there are tabs but no floating rows. + adapterHolder.mPadding.top = 0; + } else { + adapterHolder.mPadding.top = padding; + } adapterHolder.applyPadding(); if (adapterHolder.mRecyclerView != null) { adapterHolder.mRecyclerView.scrollToTop(); } - }); + } removeCustomRules(mHeader); if (!isSearchSupported()) { @@ -862,13 +871,15 @@ private void layoutBelowSearchContainer(View v, boolean includeTabsMargin) { } RelativeLayout.LayoutParams layoutParams = (LayoutParams) v.getLayoutParams(); - layoutParams.addRule(RelativeLayout.ALIGN_TOP, R.id.search_container_all_apps); + layoutParams.addRule(RelativeLayout.BELOW, R.id.search_container_all_apps); int topMargin = getContext().getResources().getDimensionPixelSize( - R.dimen.all_apps_header_top_margin); + R.dimen.all_apps_search_bar_bottom_adjustment); if (includeTabsMargin) { topMargin += getContext().getResources().getDimensionPixelSize( - R.dimen.all_apps_header_pill_height); + R.dimen.all_apps_header_pill_height) + + getContext().getResources().getDimensionPixelSize( + R.dimen.all_apps_tabs_margin_top); } layoutParams.topMargin = topMargin; } @@ -896,6 +907,7 @@ private void removeCustomRules(View v) { layoutParams.removeRule(RelativeLayout.ABOVE); layoutParams.removeRule(RelativeLayout.ALIGN_TOP); layoutParams.removeRule(RelativeLayout.ALIGN_PARENT_TOP); + layoutParams.removeRule(RelativeLayout.BELOW); } protected BaseAllAppsAdapter createAdapter(AlphabeticalAppsList appsList) { diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java index 92c589c9663..fd5d15bbd60 100644 --- a/src/com/android/launcher3/allapps/FloatingHeaderView.java +++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java @@ -251,6 +251,8 @@ void setActiveRV(int rvType) { : rvType == AdapterHolder.WORK ? mWorkRV : mSearchRV; mCurrentRV.addOnScrollListener(mOnScrollListener); maybeSetTabVisibility(rvType == AdapterHolder.SEARCH ? GONE : VISIBLE); + + updateExpectedHeight(); } /** Update tab visibility to the given state, only if tabs are active (work profile exists). */ @@ -265,10 +267,7 @@ private void updateExpectedHeight() { return; } mMaxTranslation += mFloatingRowsHeight; - if (!mTabsHidden) { - mMaxTranslation += mTabsAdditionalPaddingBottom - + getResources().getDimensionPixelSize(R.dimen.all_apps_tabs_margin_top); - } + // No need for mMaxTranslation to be any taller now that we align below the header. } int getMaxTranslation() { From dcc83be2f84c1f65cb36e71bf9a0a4f5c0f9a4be Mon Sep 17 00:00:00 2001 From: Tommy Webb Date: Mon, 16 Jan 2023 18:53:37 -0500 Subject: [PATCH 010/164] DerpLauncher: Skip glitchy search animation * Entering and leaving search now takes effect right away. * Should fix race in which tapping an app while search results are loading causes a tap on the previous app in the position, rather than on the search result. * Helps prevent the scrollbar from appearing to be scrolled down somewhat when leaving search with floating header rows present; still happens sometimes, though (on stock OS launcher, too). Issue: calyxos#1413 Change-Id: I67bc59456eb2e57e13b1b99509d3313ff0243b88 --- .../launcher3/allapps/ActivityAllAppsContainerView.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java index b89dd1e10c8..41383dec0d1 100644 --- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java @@ -129,7 +129,8 @@ public void setValue(ActivityAllAppsContainerView containerView, float v) { public static final float PULL_MULTIPLIER = .02f; public static final float FLING_VELOCITY_MULTIPLIER = 1200f; protected static final String BUNDLE_KEY_CURRENT_PAGE = "launcher.allapps.current_page"; - private static final long DEFAULT_SEARCH_TRANSITION_DURATION_MS = 300; + // As of this writing, search transition does not seem to work properly, so set duration to 0. + private static final long DEFAULT_SEARCH_TRANSITION_DURATION_MS = 0; // Render the header protection at all times to debug clipping issues. private static final boolean DEBUG_HEADER_PROTECTION = false; /** Context of an activity or window that is inflating this container. */ From 794c30a26247770abc92f56f41af5549561a3b3e Mon Sep 17 00:00:00 2001 From: Adithya R Date: Thu, 6 Oct 2022 17:51:11 +0530 Subject: [PATCH 011/164] DerpLauncher: Improve search bar header protection neobuddy89: When app label in app drawer is disabled, there is an overlap. Before: https://imgur.com/H2eQGer After: https://imgur.com/4YqAN4Z Signed-off-by: Pranav Vashi --- res/values/dimens.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 74dce62459d..02e127d9b99 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -100,12 +100,12 @@ 300dp - 48dp + 52dp - 24dp + 26dp - 24dp + 42dp -6dp @@ -115,14 +115,14 @@ 12dp 48dp 2dp - 33dp + 48dp 36dp 16dp - 10dp + 12dp 6dp 4dp 16dp From c3325812c33712edbab17a15b596fafa458ef904 Mon Sep 17 00:00:00 2001 From: dantmnf Date: Sat, 18 Feb 2023 14:31:11 +0800 Subject: [PATCH 012/164] DerpLauncher: Fix sorting in zh-Hans-CN Sorting behavior is different in the exact locale "zh-CN", but newer setups will have "zh-Hans-CN" and miss the locale-specific behavior. P.S. "zh-CN" locale is no longer accessible in settings UI. Change-Id: I59afe38e1ea2ac507ff017e855d9810092604e99 --- res/values-zh-rCN/derp_config.xml | 11 +++++++++++ res/values/derp_config.xml | 11 +++++++++++ .../launcher3/allapps/AlphabeticalAppsList.java | 7 +++---- 3 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 res/values-zh-rCN/derp_config.xml create mode 100644 res/values/derp_config.xml diff --git a/res/values-zh-rCN/derp_config.xml b/res/values-zh-rCN/derp_config.xml new file mode 100644 index 00000000000..c16313184b3 --- /dev/null +++ b/res/values-zh-rCN/derp_config.xml @@ -0,0 +1,11 @@ + + + + + + true + diff --git a/res/values/derp_config.xml b/res/values/derp_config.xml new file mode 100644 index 00000000000..686500eb934 --- /dev/null +++ b/res/values/derp_config.xml @@ -0,0 +1,11 @@ + + + + + + false + diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java index 5d03a932547..cc99aaa23fc 100644 --- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java +++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java @@ -40,7 +40,6 @@ import java.util.ArrayList; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.TreeMap; @@ -102,6 +101,7 @@ public FastScrollSectionInfo(CharSequence sectionName, int position) { private int mNumAppsPerRowAllApps; private int mNumAppRowsInAdapter; private Predicate mItemFilter; + private final boolean mSortSections; public AlphabeticalAppsList(Context context, @Nullable AllAppsStore appsStore, WorkProfileManager workProfileManager, PrivateProfileManager privateProfileManager) { @@ -118,6 +118,7 @@ public AlphabeticalAppsList(Context context, @Nullable AllAppsStore appsStore mPrivateProfileAppScrollerBadge.setSpan(new ImageSpan(context, R.drawable.ic_private_profile_app_scroller_badge, ImageSpan.ALIGN_CENTER), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + mSortSections = context.getResources().getBoolean(R.bool.config_appsListSortSections); } /** Set the number of apps per row when device profile changes. */ @@ -239,9 +240,7 @@ public void onAppsUpdated() { // As a special case for some languages (currently only Simplified Chinese), we may need to // coalesce sections - Locale curLocale = mActivityContext.getResources().getConfiguration().locale; - boolean localeRequiresSectionSorting = curLocale.equals(Locale.SIMPLIFIED_CHINESE); - if (localeRequiresSectionSorting) { + if (mSortSections) { // Compute the section headers. We use a TreeMap with the section name comparator to // ensure that the sections are ordered when we iterate over it later appSteam = appSteam.collect(Collectors.groupingBy( From c967a48f74336a0f1dc3df506653ab22a5bff84a Mon Sep 17 00:00:00 2001 From: Tommy Webb Date: Wed, 14 Dec 2022 16:13:06 -0500 Subject: [PATCH 013/164] DerpLauncher: Use different badges for different work profiles * Supply the UserHandle to BitmapIcon, rather than FLAG_WORK, so that the proper badge icon can be used for a given profile (different colors). Change-Id: I64f1b425eee5cc7994616050411a881d84ece99d --- .../src/com/android/quickstep/TaskIconCache.java | 13 ++++++++----- src/com/android/launcher3/Utilities.java | 16 ++++++++++------ src/com/android/launcher3/icons/IconCache.java | 4 +++- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/quickstep/src/com/android/quickstep/TaskIconCache.java b/quickstep/src/com/android/quickstep/TaskIconCache.java index e6febff5f72..8a53e52d4ad 100644 --- a/quickstep/src/com/android/quickstep/TaskIconCache.java +++ b/quickstep/src/com/android/quickstep/TaskIconCache.java @@ -232,11 +232,14 @@ private Drawable getDefaultIcon(int userId) { if ((index = mDefaultIcons.indexOfKey(userId)) >= 0) { return mDefaultIcons.valueAt(index).newIcon(mContext); } else { - BitmapInfo info = mDefaultIconBase.withFlags( - UserCache.INSTANCE.get(mContext).getUserInfo(UserHandle.of(userId)) - .applyBitmapInfoFlags(FlagOp.NO_OP)); - mDefaultIcons.put(userId, info); - return info.newIcon(mContext); + try (BaseIconFactory li = getIconFactory()) { + BitmapInfo info = mDefaultIconBase.withFlags( + UserCache.INSTANCE.get(mContext).getUserInfo(UserHandle.of(userId)) + .applyBitmapInfoFlags(FlagOp.NO_OP)) + .withUser(UserHandle.of(userId), li); + mDefaultIcons.put(userId, info); + return info.newIcon(mContext); + } } } } diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index 19a3002665f..6b862256ef4 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -595,7 +595,9 @@ public static ActivityOptions allowBGLaunch(ActivityOptions options) { Drawable badge = null; if ((info instanceof ItemInfoWithIcon iiwi) && !iiwi.usingLowResIcon()) { - badge = iiwi.bitmap.getBadgeDrawable(context, useTheme); + try (LauncherIcons li = LauncherIcons.obtain(context)) { + badge = iiwi.bitmap.withUser(iiwi.user, li).getBadgeDrawable(context, useTheme); + } } if (info instanceof PendingAddShortcutInfo) { @@ -678,11 +680,13 @@ public static ActivityOptions allowBGLaunch(ActivityOptions options) { } if (badge == null) { - badge = BitmapInfo.LOW_RES_INFO.withFlags( - UserCache.INSTANCE.get(context) - .getUserInfo(info.user) - .applyBitmapInfoFlags(FlagOp.NO_OP)) - .getBadgeDrawable(context, useTheme); + try (LauncherIcons li = LauncherIcons.obtain(context)) { + badge = BitmapInfo.LOW_RES_INFO.withUser(info.user, li).withFlags( + UserCache.INSTANCE.get(context) + .getUserInfo(info.user) + .applyBitmapInfoFlags(FlagOp.NO_OP)) + .getBadgeDrawable(context, useTheme); + } if (badge == null) { badge = new ColorDrawable(Color.TRANSPARENT); } diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java index 44e448eea11..91b8ed77245 100644 --- a/src/com/android/launcher3/icons/IconCache.java +++ b/src/com/android/launcher3/icons/IconCache.java @@ -592,7 +592,9 @@ private synchronized BitmapInfo getBadgedIcon(@Nullable final BitmapInfo bitmap, if (bitmap == null) { return getDefaultIcon(user); } - return bitmap.withFlags(getUserFlagOpLocked(user)); + try (BaseIconFactory bif = getIconFactory()) { + return bitmap.withUser(user, bif); + } } protected void applyCacheEntry(@NonNull final CacheEntry entry, From 7b947e5d6ad1d460dd7ecd11292f13a8c277953f Mon Sep 17 00:00:00 2001 From: Sebastiano Barezzi Date: Sat, 27 Jan 2024 05:19:24 +0100 Subject: [PATCH 014/164] DerpLauncher: Fix TaskbarModelCallbacksFactory instantiation Overrides.getObject() calls the constructor with context if the overlay has a valid class, if empty it uses the constructor without args. Considering this class is part of quickstep, we should support both cases, since this is the fallback class anyway Change-Id: Ic412a2a3efbe1d3f8b9c02a58635c2821eabd54d --- .../launcher3/taskbar/TaskbarModelCallbacksFactory.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacksFactory.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacksFactory.kt index eb03b4abc51..8531729fb5c 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacksFactory.kt +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacksFactory.kt @@ -22,7 +22,10 @@ import com.android.launcher3.util.ResourceBasedOverride import com.android.launcher3.util.ResourceBasedOverride.Overrides /** Creates [TaskbarModelCallbacks] instances. */ -open class TaskbarModelCallbacksFactory : ResourceBasedOverride { +// We must have constructors with and without context for Overrides.getObject +open class TaskbarModelCallbacksFactory @JvmOverloads constructor( + context: Context? = null +) : ResourceBasedOverride { open fun create( activityContext: TaskbarActivityContext, From 3102506983ac9e040aa97179891e1c3681304636 Mon Sep 17 00:00:00 2001 From: Aaron Kling Date: Tue, 27 Aug 2024 23:40:41 -0500 Subject: [PATCH 015/164] DerpLauncher: Fix TaskbarViewCallbacksFactory instantiation Overrides.getObject() calls the constructor with context if the overlay has a valid class, if empty it uses the constructor without args. Considering this class is part of quickstep, we should support both cases, since this is the fallback class anyway Based on 93f44a4 Change-Id: Ida3f5e056522871dc35ce48a5488ad28b6b0c2cc --- .../android/launcher3/taskbar/TaskbarViewCallbacksFactory.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacksFactory.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacksFactory.kt index ba0f5a01b07..47de1c4f899 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacksFactory.kt +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacksFactory.kt @@ -22,7 +22,10 @@ import com.android.launcher3.util.ResourceBasedOverride import com.android.launcher3.util.ResourceBasedOverride.Overrides /** Creates [TaskbarViewCallbacks] instances. */ -open class TaskbarViewCallbacksFactory : ResourceBasedOverride { +// We must have constructors with and without context for Overrides.getObject +open class TaskbarViewCallbacksFactory @JvmOverloads constructor( + context: Context? = null +) : ResourceBasedOverride { open fun create( activity: TaskbarActivityContext, From f677da2df9971dc2e0888c3e3ad37c0ee5b35b4e Mon Sep 17 00:00:00 2001 From: Dil3mm4 Date: Thu, 7 Jan 2021 05:40:57 +0000 Subject: [PATCH 016/164] DerpLauncher: AppsSearchContainerLayout: Avoid NPE Change-Id: I29aac5482ab3a6e8df41fd130013fd9ff0c3c8e6 --- .../launcher3/allapps/search/AppsSearchContainerLayout.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java index d83efd6c16f..88b02235f5f 100644 --- a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java +++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java @@ -85,13 +85,15 @@ public AppsSearchContainerLayout(Context context, AttributeSet attrs, int defSty @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); - mAppsView.getAppsStore().addUpdateListener(this); + if(mAppsView != null) + mAppsView.getAppsStore().addUpdateListener(this); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - mAppsView.getAppsStore().removeUpdateListener(this); + if(mAppsView != null) + mAppsView.getAppsStore().removeUpdateListener(this); } @Override From 76edb9f8eeeda375905ab81df4632aab515c83fe Mon Sep 17 00:00:00 2001 From: Pranav Vashi Date: Sat, 22 Apr 2023 23:04:56 +0530 Subject: [PATCH 017/164] DerpLauncher: Add NPE check in TaskbarDragController Fixes: https://github.com/crdroidandroid/issue_tracker/issues/173 Signed-off-by: Pranav Vashi --- .../com/android/launcher3/taskbar/TaskbarDragController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java index 4f5922c29fc..d29acfcdf05 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java @@ -510,7 +510,7 @@ public boolean isSystemDragInProgress() { } private void maybeOnDragEnd() { - if (!isDragging()) { + if (mDragObject != null && !isDragging()) { ((BubbleTextView) mDragObject.originalView).setIconDisabled(false); mControllers.taskbarAutohideSuspendController.updateFlag( TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_DRAGGING, false); @@ -529,7 +529,7 @@ private void maybeOnDragEnd() { @Override protected void endDrag() { - if (mDisallowGlobalDrag) { + if (mDragObject != null && mDisallowGlobalDrag) { // We need to explicitly set deferDragViewCleanupPostAnimation to true here so the // super call doesn't remove it from the drag layer before the animation completes. // This variable gets set in to false in super.dispatchDropComplete() because it From a64956d0496b8cfa0012c0d98df6ea3a9630663f Mon Sep 17 00:00:00 2001 From: minaripenguin Date: Sun, 21 May 2023 19:58:02 +0800 Subject: [PATCH 018/164] DerpLauncher: Prevent NPE when using custom themed icons Change-Id: I0405f96b8bfd1e7beaca518a06c9c4520b578b6d Signed-off-by: minaripenguin --- src/com/android/launcher3/icons/LauncherIconProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/android/launcher3/icons/LauncherIconProvider.java b/src/com/android/launcher3/icons/LauncherIconProvider.java index c4d5f2b5b56..6986578be9b 100644 --- a/src/com/android/launcher3/icons/LauncherIconProvider.java +++ b/src/com/android/launcher3/icons/LauncherIconProvider.java @@ -90,7 +90,7 @@ private Map getThemedIconMap() { if (TAG_ICON.equals(parser.getName())) { String pkg = parser.getAttributeValue(null, ATTR_PACKAGE); int iconId = parser.getAttributeResourceValue(null, ATTR_DRAWABLE, 0); - if (iconId != 0 && !TextUtils.isEmpty(pkg)) { + if (iconId != 0 && pkg != null && !pkg.isEmpty()) { map.put(pkg, new ThemeData(res, iconId)); } } From a48ca7189e4fa483ea8eff9188cd16b67b6686cb Mon Sep 17 00:00:00 2001 From: yingrenw Date: Tue, 3 Jan 2017 20:05:15 +0800 Subject: [PATCH 019/164] DerpLauncher: Stability NullPointer issue Description: Compute a child location by recursion, it may not have parent view. When the child doesn't have parent, should break the recursive. Change-Id: I8707712b85c10bf1c1d3860c5b8323aefd455cf2 CRs-Fixed: 1104931 --- src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java b/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java index 21d157a41b2..7590828fe68 100644 --- a/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java +++ b/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java @@ -90,7 +90,7 @@ private void computeLocationRelativeToContainer(View child, Rect outRect) { } View parent = (View) child.getParent(); - if (parent != mContainer) { + if (parent != null && parent != mContainer) { if (parent instanceof PagedView) { PagedView page = (PagedView) parent; outRect.left -= page.getScrollForPage(page.indexOfChild(child)); From 496c0614665a41861fe5c825573417ad4b2a4bfb Mon Sep 17 00:00:00 2001 From: Harsh Date: Thu, 2 Mar 2023 00:52:29 +0530 Subject: [PATCH 020/164] DerpLauncher: PageIndicatorDots: null pointer Exception --- .../android/launcher3/pageindicators/PageIndicatorDots.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java index e44ea1d69d0..e2b1844265f 100644 --- a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java +++ b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java @@ -187,6 +187,10 @@ public void setScroll(int currentScroll, int totalScroll) { mTotalScroll = totalScroll; int scrollPerPage = totalScroll / (mNumPages - 1); + if (scrollPerPage == 0) { + return; + } + int pageToLeft = scrollPerPage == 0 ? 0 : currentScroll / scrollPerPage; int pageToLeftScroll = pageToLeft * scrollPerPage; int pageToRightScroll = pageToLeftScroll + scrollPerPage; From 90f2032d4e10c9c5be85d2cd20e910af93853eb1 Mon Sep 17 00:00:00 2001 From: Anle Pan Date: Mon, 24 Apr 2023 14:23:08 +0000 Subject: [PATCH 021/164] DerpLauncher: Fix monkey crash in RecentsLaunchAnimator It will appear a null object crash in quickstep launch when monkey test. Althoough the 'View v' is declared as NonNull, but there is a probability that it will return a null object after the 'isTaskViewVisible' judgement in 'findTaskViewToLaunch', Make a judgement before use to avoid crash. Change-Id: I4606853325641feaf26a79791cce2514cee80d4c Signed-off-by: Anle Pan --- quickstep/src/com/android/quickstep/TaskViewUtils.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java index ecd84f865f2..9dace7c1ce5 100644 --- a/quickstep/src/com/android/quickstep/TaskViewUtils.java +++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java @@ -601,6 +601,9 @@ public static void composeRecentsLaunchAnimator(@NonNull AnimatorSet anim, @NonN boolean skipLauncherChanges = !launcherClosing; TaskView taskView = findTaskViewToLaunch(recentsView, v, appTargets); + if (taskView == null) { + return; + } PendingAnimation pa = new PendingAnimation(RECENTS_LAUNCH_DURATION); createRecentsWindowAnimator(recentsView, taskView, skipLauncherChanges, appTargets, wallpaperTargets, nonAppTargets, depthController, pa); From 39a8be1302f16be32880198b2ab12decaea161d6 Mon Sep 17 00:00:00 2001 From: Suphon Thanakornpakapong Date: Mon, 11 Oct 2021 11:26:26 +0700 Subject: [PATCH 022/164] DerpLauncher: Fix crash when placing widgets Change-Id: Id7800817bd869fa28eeddf31384777720b95b32c --- .../android/launcher3/model/data/LauncherAppWidgetInfo.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java b/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java index f4dda5593a5..04a14d27b56 100644 --- a/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java +++ b/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java @@ -236,13 +236,13 @@ private static int computeWidgetFeatures( if (ATLEAST_S && providerInfo.previewLayout != Resources.ID_NULL) { widgetFeatures |= FEATURE_PREVIEW_LAYOUT; } - if (ATLEAST_S && providerInfo.targetCellWidth > 0 || providerInfo.targetCellHeight > 0) { + if (ATLEAST_S && (providerInfo.targetCellWidth > 0 || providerInfo.targetCellHeight > 0)) { widgetFeatures |= FEATURE_TARGET_CELL_SIZE; } if (providerInfo.minResizeWidth > 0 || providerInfo.minResizeHeight > 0) { widgetFeatures |= FEATURE_MIN_SIZE; } - if (ATLEAST_S && providerInfo.maxResizeWidth > 0 || providerInfo.maxResizeHeight > 0) { + if (ATLEAST_S && (providerInfo.maxResizeWidth > 0 || providerInfo.maxResizeHeight > 0)) { widgetFeatures |= FEATURE_MAX_SIZE; } if (hostView instanceof LauncherAppWidgetHostView && From 590203c8689ffd2fb3f6a8c5905661712294a09a Mon Sep 17 00:00:00 2001 From: Anle Pan Date: Fri, 14 Apr 2023 14:13:23 +0000 Subject: [PATCH 023/164] DerpLauncher: Fix monkey crash in createSurfaceParams it will appear a null object reference crash in quickstep lanch when monkey test, make a non-null judgement before use to avoid crash Change-Id: I0d92a9c3fa4d5836247b40c96a262c35eb6c1ea9 Signed-off-by: Anle Pan --- .../src/com/android/quickstep/util/TaskViewSimulator.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java index 49f4e5f701b..6de89e0377e 100644 --- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java +++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java @@ -494,9 +494,11 @@ public void apply(TransformParams params, @Nullable SurfaceTransaction surfaceTr mInversePositionMatrix.mapRect(mTempRectF); mTempRectF.roundOut(mTmpCropRect); - params.setProgress(1f - fullScreenProgress); - params.applySurfaceParams(surfaceTransaction == null - ? params.createSurfaceParams(this) : surfaceTransaction); + if (params.getTargetSet() != null) { + params.setProgress(1f - fullScreenProgress); + params.applySurfaceParams(surfaceTransaction == null + ? params.createSurfaceParams(this) : surfaceTransaction); + } if (!DEBUG) { return; From eedfedfd7458980942314814944fe7c471132d79 Mon Sep 17 00:00:00 2001 From: Shen Lin Date: Mon, 13 Mar 2023 17:46:42 +0800 Subject: [PATCH 024/164] DerpLauncher: Fix crash in SurfaceTransactionApplier Calling getViewRootImpl on a targetView is nullable, so we'd add a null check here before getting its SurfaceControl. Bug: 273143527 Test: manual Change-Id: I245bc553ca32cf5b86978f826cfb2ca92def84d7 --- .../com/android/quickstep/util/SurfaceTransactionApplier.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java b/quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java index a26d056da1a..2a4a77b86df 100644 --- a/quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java +++ b/quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java @@ -73,7 +73,8 @@ public void onViewDetachedFromWindow(View v) { private void initialize(View view) { mTargetViewRootImpl = view.getViewRootImpl(); - mBarrierSurfaceControl = mTargetViewRootImpl.getSurfaceControl(); + mBarrierSurfaceControl = + mTargetViewRootImpl != null ? mTargetViewRootImpl.getSurfaceControl() : null; mInitialized = true; } From 8a25a9b285d48a32de4e5a2e358aa06cedca6fba Mon Sep 17 00:00:00 2001 From: Leonardo Hvang Date: Sat, 23 Jul 2022 01:51:36 +0800 Subject: [PATCH 025/164] DerpLauncher: Fix rtl layout error Fix location of AllAppsEduView not center in rtl layout. Test: manual - swipe up to trigger AllAppsEduView in different situation Change-Id: I8185148fda34200052fd520d2ca865b81bca270a --- quickstep/src/com/android/quickstep/views/AllAppsEduView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickstep/src/com/android/quickstep/views/AllAppsEduView.java b/quickstep/src/com/android/quickstep/views/AllAppsEduView.java index 121d8ede11c..b90da50f1fa 100644 --- a/quickstep/src/com/android/quickstep/views/AllAppsEduView.java +++ b/quickstep/src/com/android/quickstep/views/AllAppsEduView.java @@ -267,7 +267,7 @@ private void init(Launcher launcher) { DeviceProfile grid = launcher.getDeviceProfile(); DragLayer.LayoutParams lp = new DragLayer.LayoutParams(mWidthPx, mMaxHeightPx); lp.ignoreInsets = true; - lp.leftMargin = (grid.widthPx - mWidthPx) / 2; + lp.setMarginStart((grid.widthPx - mWidthPx) / 2); lp.topMargin = grid.heightPx - grid.hotseatBarSizePx - mMaxHeightPx; setLayoutParams(lp); } From 5e64c6d89f284bfa805c4231354e6ba8de4aecf3 Mon Sep 17 00:00:00 2001 From: Shen Lin Date: Thu, 2 Mar 2023 11:38:27 +0800 Subject: [PATCH 026/164] DerpLauncher: Fix potential ConcurrentModificationException The workspaceItemInfos passed in may be modified elsewhere at the same time as this executor is running, we can introduce a new ArrayList object initialized with all original workspaceItemInfos to avoid ConcurrentModificationException as a tricky workaround. Bug: 271324475 Test: atest Change-Id: I087e2b780a35743b8f9cb1371dd13fa241737f8c --- .../launcher3/folder/FolderNameProvider.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/com/android/launcher3/folder/FolderNameProvider.java b/src/com/android/launcher3/folder/FolderNameProvider.java index be5f8f76efe..c408946a933 100644 --- a/src/com/android/launcher3/folder/FolderNameProvider.java +++ b/src/com/android/launcher3/folder/FolderNameProvider.java @@ -48,6 +48,8 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.function.Function; +import java.util.function.Predicate; import java.util.stream.Collectors; /** @@ -111,9 +113,11 @@ public void getSuggestedFolderName(Context context, Log.d(TAG, "getSuggestedFolderName:" + nameInfos.toString()); } + // A shallow copy tring to avoid ConcurrentModificationException + final ArrayList candidates = new ArrayList<>(workspaceItemInfos); // If all the icons are from work profile, // Then, suggest "Work" as the folder name - Set users = workspaceItemInfos.stream().map(w -> w.user) + Set users = candidates.stream().map(w -> w.user) .collect(Collectors.toSet()); if (users.size() == 1 && !users.contains(Process.myUserHandle())) { setAsLastSuggestion(nameInfos, getWorkFolderName(context)); @@ -121,10 +125,9 @@ public void getSuggestedFolderName(Context context, // If all the icons are from same package (e.g., main icon, shortcut, shortcut) // Then, suggest the package's title as the folder name - Set packageNames = workspaceItemInfos.stream() - .map(WorkspaceItemInfo::getTargetComponent) - .filter(Objects::nonNull) - .map(ComponentName::getPackageName) + Set packageNames = candidates.stream() + .filter(workspaceItemInfo -> workspaceItemInfo.getTargetComponent() != null) + .map(workspaceItemInfo -> workspaceItemInfo.getTargetComponent().getPackageName()) .collect(Collectors.toSet()); if (packageNames.size() == 1) { From 51eb8d9a93ad7e44d16670838f040d398e6c7449 Mon Sep 17 00:00:00 2001 From: Alex Cruz Date: Tue, 13 Dec 2022 23:19:47 +0530 Subject: [PATCH 027/164] DerpLauncher: Elevate to 'core/platform' app Change-Id: I9e6c5f2f1be9d823783eeeb0bb6a13b686a03728 --- Android.bp | 4 ++++ AndroidManifest-common.xml | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Android.bp b/Android.bp index c3f1b8699fb..a612088e23d 100644 --- a/Android.bp +++ b/Android.bp @@ -198,6 +198,7 @@ android_app { sdk_version: "current", min_sdk_version: min_launcher3_sdk_version, target_sdk_version: "current", + certificate: "platform", privileged: true, system_ext_specific: true, @@ -310,6 +311,7 @@ android_app { min_sdk_version: "current", target_sdk_version: "current", + certificate: "platform", privileged: true, system_ext_specific: true, overrides: [ @@ -354,6 +356,7 @@ android_app { enabled: true, }, + certificate: "platform", privileged: true, system_ext_specific: true, overrides: [ @@ -392,6 +395,7 @@ android_app { enabled: true, }, + certificate: "platform", privileged: true, system_ext_specific: true, overrides: [ diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml index b0e1a834a8b..ed01c05f76e 100644 --- a/AndroidManifest-common.xml +++ b/AndroidManifest-common.xml @@ -20,7 +20,9 @@ + package="com.android.launcher3" + coreApp="true" + android:sharedUserId="android.uid.system"> @@ -158,6 +158,46 @@ + + + + + + + + + + + + + + + + + diff --git a/res/drawable/ic_settings_homescreen.xml b/res/drawable/ic_settings_homescreen.xml new file mode 100644 index 00000000000..a7927f90adf --- /dev/null +++ b/res/drawable/ic_settings_homescreen.xml @@ -0,0 +1,7 @@ + + + diff --git a/res/drawable/ic_settings_icons.xml b/res/drawable/ic_settings_icons.xml new file mode 100644 index 00000000000..d7cc114b543 --- /dev/null +++ b/res/drawable/ic_settings_icons.xml @@ -0,0 +1,7 @@ + + + diff --git a/res/drawable/ic_settings_misc.xml b/res/drawable/ic_settings_misc.xml new file mode 100644 index 00000000000..dd7b3e24613 --- /dev/null +++ b/res/drawable/ic_settings_misc.xml @@ -0,0 +1,10 @@ + + + + diff --git a/res/drawable/ic_settings_recents.xml b/res/drawable/ic_settings_recents.xml new file mode 100644 index 00000000000..f719ab26b54 --- /dev/null +++ b/res/drawable/ic_settings_recents.xml @@ -0,0 +1,7 @@ + + + diff --git a/res/layout/settings_layout.xml b/res/layout/settings_layout.xml new file mode 100644 index 00000000000..2365d67d18b --- /dev/null +++ b/res/layout/settings_layout.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + diff --git a/res/values-de/derp_strings.xml b/res/values-de/derp_strings.xml new file mode 100644 index 00000000000..36ce176887d --- /dev/null +++ b/res/values-de/derp_strings.xml @@ -0,0 +1,28 @@ + + + + + + Startbildschirm-Einstellungen + + + Startbildschirm + Google-Now-Panel einstellen und mehr + Symbole + Symbolgröße und weiteres anpassen + App-Übersicht + App-Übersicht konfigurieren + App-Verlauf + Anpassen des App-Verlaufs + Sonstiges + Andere Optionen + Allgemein + Benutzeroberfläche + + + Entwickler-Optionen + Einige versteckte Funktionen auf eigene Gefahr aktivieren + diff --git a/res/values/derp_config.xml b/res/values/derp_config.xml index 686500eb934..4cb1f914e48 100644 --- a/res/values/derp_config.xml +++ b/res/values/derp_config.xml @@ -8,4 +8,19 @@ false + + + com.android.launcher3.settings.SettingsAppDrawer$AppDrawerSettingsFragment + + + com.android.launcher3.settings.SettingsHomescreen$HomescreenSettingsFragment + + + com.android.launcher3.settings.SettingsIcons$IconsSettingsFragment + + + com.android.launcher3.settings.SettingsMisc$MiscSettingsFragment + + + com.android.launcher3.settings.SettingsRecents$RecentsSettingsFragment diff --git a/res/values/derp_strings.xml b/res/values/derp_strings.xml index 489b2a3df16..9d807490aca 100644 --- a/res/values/derp_strings.xml +++ b/res/values/derp_strings.xml @@ -3,11 +3,32 @@ Copyright (C) 2023 DerpFest SPDX-License-Identifier: Apache-2.0 --> - + DerpLauncher Google + + + Home settings + + + Home screen + Set Google now panel and more + Icons + Set icon size and more + App drawer + Customize your app drawer + Recents + Revamp the overview screen + Miscellaneous + Other options + General + Interface + + + Developer options + Enable some hidden features at your own risk diff --git a/res/xml/launcher_app_drawer_preferences.xml b/res/xml/launcher_app_drawer_preferences.xml new file mode 100644 index 00000000000..044dc4e0e20 --- /dev/null +++ b/res/xml/launcher_app_drawer_preferences.xml @@ -0,0 +1,22 @@ + + + + + diff --git a/res/xml/launcher_home_screen_preferences.xml b/res/xml/launcher_home_screen_preferences.xml new file mode 100644 index 00000000000..05a5a8c74d3 --- /dev/null +++ b/res/xml/launcher_home_screen_preferences.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + diff --git a/res/xml/launcher_icons_preferences.xml b/res/xml/launcher_icons_preferences.xml new file mode 100644 index 00000000000..3708edce784 --- /dev/null +++ b/res/xml/launcher_icons_preferences.xml @@ -0,0 +1,28 @@ + + + + + + + diff --git a/res/xml/launcher_misc_preferences.xml b/res/xml/launcher_misc_preferences.xml new file mode 100644 index 00000000000..81ec3ca1ddc --- /dev/null +++ b/res/xml/launcher_misc_preferences.xml @@ -0,0 +1,32 @@ + + + + + + + diff --git a/res/xml/launcher_preferences.xml b/res/xml/launcher_preferences.xml index 284ab9e718e..0cda62e25cc 100644 --- a/res/xml/launcher_preferences.xml +++ b/res/xml/launcher_preferences.xml @@ -18,36 +18,64 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:launcher="http://schemas.android.com/apk/res-auto"> - - - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/res/xml/launcher_recents_preferences.xml b/res/xml/launcher_recents_preferences.xml new file mode 100644 index 00000000000..044dc4e0e20 --- /dev/null +++ b/res/xml/launcher_recents_preferences.xml @@ -0,0 +1,22 @@ + + + + + diff --git a/src/com/android/launcher3/settings/SettingsActivity.java b/src/com/android/launcher3/settings/SettingsActivity.java index 52ce4e85a64..5899861e982 100644 --- a/src/com/android/launcher3/settings/SettingsActivity.java +++ b/src/com/android/launcher3/settings/SettingsActivity.java @@ -16,25 +16,16 @@ package com.android.launcher3.settings; -import static android.provider.Settings.Global.DEVELOPMENT_SETTINGS_ENABLED; - import static androidx.preference.PreferenceFragmentCompat.ARG_PREFERENCE_ROOT; -import static com.android.launcher3.BuildConfig.IS_DEBUG_DEVICE; -import static com.android.launcher3.BuildConfig.IS_STUDIO_BUILD; -import static com.android.launcher3.states.RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY; - import android.app.Activity; import android.content.Intent; -import android.net.Uri; +import android.content.SharedPreferences; import android.os.Bundle; -import android.provider.Settings; import android.text.TextUtils; import android.view.MenuItem; import android.view.View; -import androidx.annotation.Nullable; -import androidx.annotation.VisibleForTesting; import androidx.core.view.WindowCompat; import androidx.fragment.app.DialogFragment; import androidx.fragment.app.Fragment; @@ -48,24 +39,17 @@ import androidx.preference.PreferenceScreen; import androidx.recyclerview.widget.RecyclerView; -import com.android.launcher3.BuildConfig; +import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherFiles; +import com.android.launcher3.Utilities; import com.android.launcher3.R; -import com.android.launcher3.states.RotationHelper; -import com.android.launcher3.util.DisplayController; -import com.android.launcher3.util.SettingsCache; /** - * Settings activity for Launcher. Currently implements the following setting: Allow rotation + * Settings activity for Launcher. */ public class SettingsActivity extends FragmentActivity implements OnPreferenceStartFragmentCallback, OnPreferenceStartScreenCallback { - @VisibleForTesting - static final String DEVELOPER_OPTIONS_KEY = "pref_developer_options"; - - private static final String NOTIFICATION_DOTS_PREFERENCE_KEY = "pref_icon_badging"; - public static final String EXTRA_FRAGMENT_ARGS = ":settings:fragment_args"; // Intent extra to indicate the pref-key to highlighted when opening the settings activity @@ -142,7 +126,7 @@ public boolean onPreferenceStartFragment( public boolean onPreferenceStartScreen(PreferenceFragmentCompat caller, PreferenceScreen pref) { Bundle args = new Bundle(); args.putString(ARG_PREFERENCE_ROOT, pref.getKey()); - return startPreference(getString(R.string.settings_fragment_name), args, pref.getKey()); + return startPreference(getString(R.string.settings_title), args, pref.getKey()); } @Override @@ -157,27 +141,13 @@ public boolean onOptionsItemSelected(MenuItem item) { /** * This fragment shows the launcher preferences. */ - public static class LauncherSettingsFragment extends PreferenceFragmentCompat implements - SettingsCache.OnChangeListener { - - protected boolean mDeveloperOptionsEnabled = false; + public static class LauncherSettingsFragment extends PreferenceFragmentCompat { private boolean mRestartOnResume = false; private String mHighLightKey; private boolean mPreferenceHighlighted = false; - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - if (BuildConfig.IS_DEBUG_DEVICE) { - Uri devUri = Settings.Global.getUriFor(DEVELOPMENT_SETTINGS_ENABLED); - SettingsCache settingsCache = SettingsCache.INSTANCE.get(getContext()); - mDeveloperOptionsEnabled = settingsCache.getValue(devUri); - settingsCache.register(devUri, this); - } - super.onCreate(savedInstanceState); - } - @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { final Bundle args = getArguments(); @@ -190,14 +160,6 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { getPreferenceManager().setSharedPreferencesName(LauncherFiles.SHARED_PREFERENCES_KEY); setPreferencesFromResource(R.xml.launcher_preferences, rootKey); - PreferenceScreen screen = getPreferenceScreen(); - for (int i = screen.getPreferenceCount() - 1; i >= 0; i--) { - Preference preference = screen.getPreference(i); - if (!initPreference(preference)) { - screen.removePreference(preference); - } - } - if (getActivity() != null && !TextUtils.isEmpty(getPreferenceScreen().getTitle())) { getActivity().setTitle(getPreferenceScreen().getTitle()); } @@ -227,36 +189,6 @@ public void onSaveInstanceState(Bundle outState) { outState.putBoolean(SAVE_HIGHLIGHTED_KEY, mPreferenceHighlighted); } - /** - * Initializes a preference. This is called for every preference. Returning false here - * will remove that preference from the list. - */ - protected boolean initPreference(Preference preference) { - switch (preference.getKey()) { - case NOTIFICATION_DOTS_PREFERENCE_KEY: - return BuildConfig.NOTIFICATION_DOTS_ENABLED; - - case ALLOW_ROTATION_PREFERENCE_KEY: - DisplayController.Info info = - DisplayController.INSTANCE.get(getContext()).getInfo(); - if (info.isTablet(info.realBounds)) { - // Launcher supports rotation by default. No need to show this setting. - return false; - } - // Initialize the UI once - preference.setDefaultValue(RotationHelper.getAllowRotationDefaultValue(info)); - return true; - - case DEVELOPER_OPTIONS_KEY: - if (IS_STUDIO_BUILD) { - preference.setOrder(0); - } - return mDeveloperOptionsEnabled; - } - - return true; - } - @Override public void onResume() { super.onResume(); @@ -274,21 +206,6 @@ public void onResume() { } } - @Override - public void onSettingsChanged(boolean isEnabled) { - // Developer options changed, try recreate - tryRecreateActivity(); - } - - @Override - public void onDestroy() { - super.onDestroy(); - if (IS_DEBUG_DEVICE) { - SettingsCache.INSTANCE.get(getContext()) - .unregister(Settings.Global.getUriFor(DEVELOPMENT_SETTINGS_ENABLED), this); - } - } - /** * Tries to recreate the preference */ diff --git a/src/com/android/launcher3/settings/SettingsAppDrawer.java b/src/com/android/launcher3/settings/SettingsAppDrawer.java new file mode 100644 index 00000000000..3208ce736a5 --- /dev/null +++ b/src/com/android/launcher3/settings/SettingsAppDrawer.java @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.launcher3.settings; + +import static androidx.preference.PreferenceFragmentCompat.ARG_PREFERENCE_ROOT; + +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.MenuItem; +import android.view.View; + +import androidx.core.view.WindowCompat; +import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.preference.Preference; +import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.PreferenceFragmentCompat.OnPreferenceStartFragmentCallback; +import androidx.preference.PreferenceFragmentCompat.OnPreferenceStartScreenCallback; +import androidx.preference.PreferenceGroup.PreferencePositionCallback; +import androidx.preference.PreferenceScreen; +import androidx.recyclerview.widget.RecyclerView; + +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherFiles; +import com.android.launcher3.LauncherPrefs; +import com.android.launcher3.R; +import com.android.launcher3.Utilities; + +import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity; + +public class SettingsAppDrawer extends CollapsingToolbarBaseActivity + implements OnPreferenceStartFragmentCallback, OnPreferenceStartScreenCallback { + + public static final String EXTRA_FRAGMENT_ARGS = ":settings:fragment_args"; + + // Intent extra to indicate the pref-key to highlighted when opening the settings activity + public static final String EXTRA_FRAGMENT_HIGHLIGHT_KEY = ":settings:fragment_args_key"; + // Intent extra to indicate the pref-key of the root screen when opening the settings activity + public static final String EXTRA_FRAGMENT_ROOT_KEY = ARG_PREFERENCE_ROOT; + public static final String EXTRA_FRAGMENT = ":settings:fragment"; + + private static final int DELAY_HIGHLIGHT_DURATION_MILLIS = 600; + public static final String SAVE_HIGHLIGHTED_KEY = "android:preference_highlighted"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.settings_activity); + + setActionBar(findViewById(R.id.action_bar)); + WindowCompat.setDecorFitsSystemWindows(getWindow(), false); + + Intent intent = getIntent(); + if (intent.hasExtra(EXTRA_FRAGMENT_ROOT_KEY) || intent.hasExtra(EXTRA_FRAGMENT_ARGS) + || intent.hasExtra(EXTRA_FRAGMENT_HIGHLIGHT_KEY)) { + getActionBar().setDisplayHomeAsUpEnabled(true); + } + + if (savedInstanceState == null) { + Bundle args = intent.getBundleExtra(EXTRA_FRAGMENT_ARGS); + if (args == null) { + args = new Bundle(); + } + + String highlight = intent.getStringExtra(EXTRA_FRAGMENT_HIGHLIGHT_KEY); + if (!TextUtils.isEmpty(highlight)) { + args.putString(EXTRA_FRAGMENT_HIGHLIGHT_KEY, highlight); + } + String root = intent.getStringExtra(EXTRA_FRAGMENT_ROOT_KEY); + if (!TextUtils.isEmpty(root)) { + args.putString(EXTRA_FRAGMENT_ROOT_KEY, root); + } + + final FragmentManager fm = getSupportFragmentManager(); + final Fragment f = fm.getFragmentFactory().instantiate(getClassLoader(), + getString(R.string.app_drawer_settings_fragment_name)); + f.setArguments(args); + // Display the fragment as the main content. + fm.beginTransaction().replace( + com.android.settingslib.collapsingtoolbar.R.id.content_frame, f).commit(); + } + } + + private boolean startPreference(String fragment, Bundle args, String key) { + if (getSupportFragmentManager().isStateSaved()) { + // Sometimes onClick can come after onPause because of being posted on the handler. + // Skip starting new preferences in that case. + return false; + } + final FragmentManager fm = getSupportFragmentManager(); + final Fragment f = fm.getFragmentFactory().instantiate(getClassLoader(), fragment); + if (f instanceof DialogFragment) { + f.setArguments(args); + ((DialogFragment) f).show(fm, key); + } else { + startActivity(new Intent(this, SettingsAppDrawer.class) + .putExtra(EXTRA_FRAGMENT_ARGS, args)); + } + return true; + } + + @Override + public boolean onPreferenceStartFragment( + PreferenceFragmentCompat preferenceFragment, Preference pref) { + return startPreference(pref.getFragment(), pref.getExtras(), pref.getKey()); + } + + @Override + public boolean onPreferenceStartScreen(PreferenceFragmentCompat caller, PreferenceScreen pref) { + Bundle args = new Bundle(); + args.putString(ARG_PREFERENCE_ROOT, pref.getKey()); + return startPreference(getString(R.string.app_drawer_category_title), args, pref.getKey()); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + onBackPressed(); + return true; + } + return super.onOptionsItemSelected(item); + } + + /** + * This fragment shows the launcher preferences. + */ + public static class AppDrawerSettingsFragment extends PreferenceFragmentCompat { + + private String mHighLightKey; + private boolean mPreferenceHighlighted = false; + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + final Bundle args = getArguments(); + mHighLightKey = args == null ? null : args.getString(EXTRA_FRAGMENT_HIGHLIGHT_KEY); + + if (savedInstanceState != null) { + mPreferenceHighlighted = savedInstanceState.getBoolean(SAVE_HIGHLIGHTED_KEY); + } + + getPreferenceManager().setSharedPreferencesName(LauncherFiles.SHARED_PREFERENCES_KEY); + setPreferencesFromResource(R.xml.launcher_app_drawer_preferences, rootKey); + + PreferenceScreen screen = getPreferenceScreen(); + for (int i = screen.getPreferenceCount() - 1; i >= 0; i--) { + Preference preference = screen.getPreference(i); + if (!initPreference(preference)) { + screen.removePreference(preference); + } + } + + if (getActivity() != null && !TextUtils.isEmpty(getPreferenceScreen().getTitle())) { + getActivity().setTitle(getPreferenceScreen().getTitle()); + } + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + View listView = getListView(); + final int bottomPadding = listView.getPaddingBottom(); + listView.setOnApplyWindowInsetsListener((v, insets) -> { + v.setPadding( + v.getPaddingLeft(), + v.getPaddingTop(), + v.getPaddingRight(), + bottomPadding + insets.getSystemWindowInsetBottom()); + return insets.consumeSystemWindowInsets(); + }); + + // Overriding Text Direction in the Androidx preference library to support RTL + view.setTextDirection(View.TEXT_DIRECTION_LOCALE); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putBoolean(SAVE_HIGHLIGHTED_KEY, mPreferenceHighlighted); + } + + /** + * Initializes a preference. This is called for every preference. Returning false here + * will remove that preference from the list. + */ + protected boolean initPreference(Preference preference) { + return true; + } + + @Override + public void onResume() { + super.onResume(); + + if (isAdded() && !mPreferenceHighlighted) { + PreferenceHighlighter highlighter = createHighlighter(); + if (highlighter != null) { + getView().postDelayed(highlighter, DELAY_HIGHLIGHT_DURATION_MILLIS); + mPreferenceHighlighted = true; + } + } + } + + private PreferenceHighlighter createHighlighter() { + if (TextUtils.isEmpty(mHighLightKey)) { + return null; + } + + PreferenceScreen screen = getPreferenceScreen(); + if (screen == null) { + return null; + } + + RecyclerView list = getListView(); + PreferencePositionCallback callback = (PreferencePositionCallback) list.getAdapter(); + int position = callback.getPreferenceAdapterPosition(mHighLightKey); + return position >= 0 ? new PreferenceHighlighter( + list, position, screen.findPreference(mHighLightKey)) + : null; + } + } +} diff --git a/src/com/android/launcher3/settings/SettingsHomescreen.java b/src/com/android/launcher3/settings/SettingsHomescreen.java new file mode 100644 index 00000000000..ce73f6f272b --- /dev/null +++ b/src/com/android/launcher3/settings/SettingsHomescreen.java @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.launcher3.settings; + +import static androidx.preference.PreferenceFragmentCompat.ARG_PREFERENCE_ROOT; + +import static com.android.launcher3.LauncherPrefs.getDevicePrefs; + +import android.app.Activity; +import android.app.DialogFragment; +import android.app.Fragment; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.MenuItem; +import android.view.View; + +import androidx.core.view.WindowCompat; +import androidx.preference.ListPreference; +import androidx.preference.Preference.OnPreferenceChangeListener; + +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherFiles; +import com.android.launcher3.LauncherPrefs; +import com.android.launcher3.R; +import com.android.launcher3.Utilities; + +import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity; + +import java.util.Collections; +import java.util.List; + +import androidx.preference.Preference; +import androidx.preference.PreferenceFragment; +import androidx.preference.PreferenceFragment.OnPreferenceStartFragmentCallback; +import androidx.preference.PreferenceFragment.OnPreferenceStartScreenCallback; +import androidx.preference.PreferenceGroup.PreferencePositionCallback; +import androidx.preference.PreferenceScreen; +import androidx.recyclerview.widget.RecyclerView; + +public class SettingsHomescreen extends CollapsingToolbarBaseActivity + implements OnPreferenceStartFragmentCallback, OnPreferenceStartScreenCallback { + + public static final String EXTRA_FRAGMENT_ARGS = ":settings:fragment_args"; + + // Intent extra to indicate the pref-key to highlighted when opening the settings activity + public static final String EXTRA_FRAGMENT_HIGHLIGHT_KEY = ":settings:fragment_args_key"; + // Intent extra to indicate the pref-key of the root screen when opening the settings activity + public static final String EXTRA_FRAGMENT_ROOT_KEY = ARG_PREFERENCE_ROOT; + + private static final int DELAY_HIGHLIGHT_DURATION_MILLIS = 600; + public static final String SAVE_HIGHLIGHTED_KEY = "android:preference_highlighted"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.settings_activity); + + setActionBar(findViewById(R.id.action_bar)); + WindowCompat.setDecorFitsSystemWindows(getWindow(), false); + + Intent intent = getIntent(); + if (intent.hasExtra(EXTRA_FRAGMENT_ROOT_KEY) || intent.hasExtra(EXTRA_FRAGMENT_ARGS) + || intent.hasExtra(EXTRA_FRAGMENT_HIGHLIGHT_KEY)) { + getActionBar().setDisplayHomeAsUpEnabled(true); + } + + if (savedInstanceState == null) { + Bundle args = intent.getBundleExtra(EXTRA_FRAGMENT_ARGS); + if (args == null) { + args = new Bundle(); + } + + String highlight = intent.getStringExtra(EXTRA_FRAGMENT_HIGHLIGHT_KEY); + if (!TextUtils.isEmpty(highlight)) { + args.putString(EXTRA_FRAGMENT_HIGHLIGHT_KEY, highlight); + } + String root = intent.getStringExtra(EXTRA_FRAGMENT_ROOT_KEY); + if (!TextUtils.isEmpty(root)) { + args.putString(EXTRA_FRAGMENT_ROOT_KEY, root); + } + + Fragment f = Fragment.instantiate( + this, getPreferenceFragment(), args); + + getFragmentManager().beginTransaction() + .replace(R.id.content_frame, f) + .commit(); + } + LauncherPrefs.getPrefs(getApplicationContext()).registerOnSharedPreferenceChangeListener(this); + } + + /** + * Obtains the preference fragment to instantiate in this activity. + * + * @return the preference fragment class + * @throws IllegalArgumentException if the fragment is unknown to this activity + */ + private String getPreferenceFragment() { + String preferenceFragment = getIntent().getStringExtra(EXTRA_FRAGMENT_ARGS); + String defaultFragment = getString(R.string.home_screen_settings_fragment_name); + + if (TextUtils.isEmpty(preferenceFragment)) { + return defaultFragment; + } else if (!preferenceFragment.equals(defaultFragment)) { + throw new IllegalArgumentException( + "Invalid fragment for this activity: " + preferenceFragment); + } else { + return preferenceFragment; + } + } + + private boolean startPreference(String fragment, Bundle args, String key) { + if (getFragmentManager().isStateSaved()) { + // Sometimes onClick can come after onPause because of being posted on the handler. + // Skip starting new preferences in that case. + return false; + } + Fragment f = Fragment.instantiate(this, fragment, args); + if (f instanceof DialogFragment) { + ((DialogFragment) f).show(getFragmentManager(), key); + } else { + startActivity(new Intent(this, SettingsHomescreen.class) + .putExtra(EXTRA_FRAGMENT_ARGS, args)); + } + return true; + } + + @Override + public boolean onPreferenceStartFragment( + PreferenceFragment preferenceFragment, Preference pref) { + return startPreference(pref.getFragment(), pref.getExtras(), pref.getKey()); + } + + @Override + public boolean onPreferenceStartScreen(PreferenceFragment caller, PreferenceScreen pref) { + Bundle args = new Bundle(); + args.putString(ARG_PREFERENCE_ROOT, pref.getKey()); + return startPreference(getString(R.string.home_category_title), args, pref.getKey()); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + onBackPressed(); + return true; + } + return super.onOptionsItemSelected(item); + } + + /** + * This fragment shows the launcher preferences. + */ + public static class HomescreenSettingsFragment extends PreferenceFragment { + + private String mHighLightKey; + private boolean mPreferenceHighlighted = false; + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + final Bundle args = getArguments(); + mHighLightKey = args == null ? null : args.getString(EXTRA_FRAGMENT_HIGHLIGHT_KEY); + + if (savedInstanceState != null) { + mPreferenceHighlighted = savedInstanceState.getBoolean(SAVE_HIGHLIGHTED_KEY); + } + + getPreferenceManager().setSharedPreferencesName(LauncherFiles.SHARED_PREFERENCES_KEY); + setPreferencesFromResource(R.xml.launcher_home_screen_preferences, rootKey); + PreferenceScreen screen = getPreferenceScreen(); + for (int i = screen.getPreferenceCount() - 1; i >= 0; i--) { + Preference preference = screen.getPreference(i); + if (!initPreference(preference)) { + screen.removePreference(preference); + } + } + + if (getActivity() != null && !TextUtils.isEmpty(getPreferenceScreen().getTitle())) { + getActivity().setTitle(getPreferenceScreen().getTitle()); + } + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + View listView = getListView(); + final int bottomPadding = listView.getPaddingBottom(); + listView.setOnApplyWindowInsetsListener((v, insets) -> { + v.setPadding( + v.getPaddingLeft(), + v.getPaddingTop(), + v.getPaddingRight(), + bottomPadding + insets.getSystemWindowInsetBottom()); + return insets.consumeSystemWindowInsets(); + }); + + // Overriding Text Direction in the Androidx preference library to support RTL + view.setTextDirection(View.TEXT_DIRECTION_LOCALE); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putBoolean(SAVE_HIGHLIGHTED_KEY, mPreferenceHighlighted); + } + + /** + * Initializes a preference. This is called for every preference. Returning false here + * will remove that preference from the list. + */ + protected boolean initPreference(Preference preference) { + return true; + } + + @Override + public void onResume() { + super.onResume(); + + if (isAdded() && !mPreferenceHighlighted) { + PreferenceHighlighter highlighter = createHighlighter(); + if (highlighter != null) { + getView().postDelayed(highlighter, DELAY_HIGHLIGHT_DURATION_MILLIS); + mPreferenceHighlighted = true; + } + } + } + + private PreferenceHighlighter createHighlighter() { + if (TextUtils.isEmpty(mHighLightKey)) { + return null; + } + + PreferenceScreen screen = getPreferenceScreen(); + if (screen == null) { + return null; + } + + RecyclerView list = getListView(); + PreferencePositionCallback callback = (PreferencePositionCallback) list.getAdapter(); + int position = callback.getPreferenceAdapterPosition(mHighLightKey); + return position >= 0 ? new PreferenceHighlighter( + list, position, screen.findPreference(mHighLightKey)) + : null; + } + } +} diff --git a/src/com/android/launcher3/settings/SettingsIcons.java b/src/com/android/launcher3/settings/SettingsIcons.java new file mode 100644 index 00000000000..0fbe9858dfc --- /dev/null +++ b/src/com/android/launcher3/settings/SettingsIcons.java @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.launcher3.settings; + +import static androidx.preference.PreferenceFragmentCompat.ARG_PREFERENCE_ROOT; + +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.MenuItem; +import android.view.View; + +import androidx.core.view.WindowCompat; +import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.preference.Preference; +import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.PreferenceFragmentCompat.OnPreferenceStartFragmentCallback; +import androidx.preference.PreferenceFragmentCompat.OnPreferenceStartScreenCallback; +import androidx.preference.PreferenceGroup.PreferencePositionCallback; +import androidx.preference.PreferenceScreen; +import androidx.recyclerview.widget.RecyclerView; + +import com.android.launcher3.BuildConfig; +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherFiles; +import com.android.launcher3.LauncherPrefs; +import com.android.launcher3.R; +import com.android.launcher3.Utilities; +import com.android.launcher3.model.WidgetsModel; + +import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity; + +public class SettingsIcons extends CollapsingToolbarBaseActivity + implements OnPreferenceStartFragmentCallback, OnPreferenceStartScreenCallback, + SharedPreferences.OnSharedPreferenceChangeListener{ + + private static final String NOTIFICATION_DOTS_PREFERENCE_KEY = "pref_icon_badging"; + + public static final String EXTRA_FRAGMENT_ARGS = ":settings:fragment_args"; + + // Intent extra to indicate the pref-key to highlighted when opening the settings activity + public static final String EXTRA_FRAGMENT_HIGHLIGHT_KEY = ":settings:fragment_args_key"; + // Intent extra to indicate the pref-key of the root screen when opening the settings activity + public static final String EXTRA_FRAGMENT_ROOT_KEY = ARG_PREFERENCE_ROOT; + + private static final int DELAY_HIGHLIGHT_DURATION_MILLIS = 600; + public static final String SAVE_HIGHLIGHTED_KEY = "android:preference_highlighted"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.settings_activity); + + setActionBar(findViewById(R.id.action_bar)); + WindowCompat.setDecorFitsSystemWindows(getWindow(), false); + + Intent intent = getIntent(); + if (intent.hasExtra(EXTRA_FRAGMENT_ROOT_KEY) || intent.hasExtra(EXTRA_FRAGMENT_ARGS) + || intent.hasExtra(EXTRA_FRAGMENT_HIGHLIGHT_KEY)) { + getActionBar().setDisplayHomeAsUpEnabled(true); + } + + if (savedInstanceState == null) { + Bundle args = intent.getBundleExtra(EXTRA_FRAGMENT_ARGS); + if (args == null) { + args = new Bundle(); + } + + String highlight = intent.getStringExtra(EXTRA_FRAGMENT_HIGHLIGHT_KEY); + if (!TextUtils.isEmpty(highlight)) { + args.putString(EXTRA_FRAGMENT_HIGHLIGHT_KEY, highlight); + } + String root = intent.getStringExtra(EXTRA_FRAGMENT_ROOT_KEY); + if (!TextUtils.isEmpty(root)) { + args.putString(EXTRA_FRAGMENT_ROOT_KEY, root); + } + + final FragmentManager fm = getSupportFragmentManager(); + final Fragment f = fm.getFragmentFactory().instantiate(getClassLoader(), + getString(R.string.icons_settings_fragment_name)); + f.setArguments(args); + // Display the fragment as the main content. + fm.beginTransaction().replace( + com.android.settingslib.collapsingtoolbar.R.id.content_frame, f).commit(); + } + LauncherPrefs.getPrefs(getApplicationContext()).registerOnSharedPreferenceChangeListener(this); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { } + + private boolean startPreference(String fragment, Bundle args, String key) { + if (getSupportFragmentManager().isStateSaved()) { + // Sometimes onClick can come after onPause because of being posted on the handler. + // Skip starting new preferences in that case. + return false; + } + final FragmentManager fm = getSupportFragmentManager(); + final Fragment f = fm.getFragmentFactory().instantiate(getClassLoader(), fragment); + if (f instanceof DialogFragment) { + f.setArguments(args); + ((DialogFragment) f).show(fm, key); + } else { + startActivity(new Intent(this, SettingsIcons.class) + .putExtra(EXTRA_FRAGMENT_ARGS, args)); + } + return true; + } + + @Override + public boolean onPreferenceStartFragment( + PreferenceFragmentCompat preferenceFragment, Preference pref) { + return startPreference(pref.getFragment(), pref.getExtras(), pref.getKey()); + } + + @Override + public boolean onPreferenceStartScreen(PreferenceFragmentCompat caller, PreferenceScreen pref) { + Bundle args = new Bundle(); + args.putString(ARG_PREFERENCE_ROOT, pref.getKey()); + return startPreference(getString(R.string.icons_category_title), args, pref.getKey()); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + onBackPressed(); + return true; + } + return super.onOptionsItemSelected(item); + } + + /** + * This fragment shows the launcher preferences. + */ + public static class IconsSettingsFragment extends PreferenceFragmentCompat implements + SharedPreferences.OnSharedPreferenceChangeListener { + + private String mHighLightKey; + private boolean mPreferenceHighlighted = false; + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + final Bundle args = getArguments(); + mHighLightKey = args == null ? null : args.getString(EXTRA_FRAGMENT_HIGHLIGHT_KEY); + + if (savedInstanceState != null) { + mPreferenceHighlighted = savedInstanceState.getBoolean(SAVE_HIGHLIGHTED_KEY); + } + + getPreferenceManager().setSharedPreferencesName(LauncherFiles.SHARED_PREFERENCES_KEY); + setPreferencesFromResource(R.xml.launcher_icons_preferences, rootKey); + + updatePreferences(); + + LauncherPrefs.getPrefs(getContext()) + .registerOnSharedPreferenceChangeListener(this); + } + + @Override + public void onDestroyView () { + LauncherPrefs.getPrefs(getContext()) + .unregisterOnSharedPreferenceChangeListener(this); + super.onDestroyView(); + } + + private void updatePreferences() { + PreferenceScreen screen = getPreferenceScreen(); + for (int i = screen.getPreferenceCount() - 1; i >= 0; i--) { + Preference preference = screen.getPreference(i); + if (!initPreference(preference)) { + screen.removePreference(preference); + } + } + + if (getActivity() != null && !TextUtils.isEmpty(getPreferenceScreen().getTitle())) { + getActivity().setTitle(getPreferenceScreen().getTitle()); + } + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + View listView = getListView(); + final int bottomPadding = listView.getPaddingBottom(); + listView.setOnApplyWindowInsetsListener((v, insets) -> { + v.setPadding( + v.getPaddingLeft(), + v.getPaddingTop(), + v.getPaddingRight(), + bottomPadding + insets.getSystemWindowInsetBottom()); + return insets.consumeSystemWindowInsets(); + }); + + // Overriding Text Direction in the Androidx preference library to support RTL + view.setTextDirection(View.TEXT_DIRECTION_LOCALE); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putBoolean(SAVE_HIGHLIGHTED_KEY, mPreferenceHighlighted); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { } + + /** + * Initializes a preference. This is called for every preference. Returning false here + * will remove that preference from the list. + */ + protected boolean initPreference(Preference preference) { + switch (preference.getKey()) { + case NOTIFICATION_DOTS_PREFERENCE_KEY: + return BuildConfig.NOTIFICATION_DOTS_ENABLED; + } + + return true; + } + + @Override + public void onResume() { + super.onResume(); + + if (isAdded() && !mPreferenceHighlighted) { + PreferenceHighlighter highlighter = createHighlighter(); + if (highlighter != null) { + getView().postDelayed(highlighter, DELAY_HIGHLIGHT_DURATION_MILLIS); + mPreferenceHighlighted = true; + } + } + } + + private PreferenceHighlighter createHighlighter() { + if (TextUtils.isEmpty(mHighLightKey)) { + return null; + } + + PreferenceScreen screen = getPreferenceScreen(); + if (screen == null) { + return null; + } + + RecyclerView list = getListView(); + PreferencePositionCallback callback = (PreferencePositionCallback) list.getAdapter(); + int position = callback.getPreferenceAdapterPosition(mHighLightKey); + return position >= 0 ? new PreferenceHighlighter( + list, position, screen.findPreference(mHighLightKey)) + : null; + } + } + + public interface OnResumePreferenceCallback { + void onResume(); + } +} diff --git a/src/com/android/launcher3/settings/SettingsMisc.java b/src/com/android/launcher3/settings/SettingsMisc.java new file mode 100644 index 00000000000..29a43bc7105 --- /dev/null +++ b/src/com/android/launcher3/settings/SettingsMisc.java @@ -0,0 +1,360 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.launcher3.settings; + +import static android.provider.Settings.Global.DEVELOPMENT_SETTINGS_ENABLED; + +import static androidx.preference.PreferenceFragmentCompat.ARG_PREFERENCE_ROOT; + +import static com.android.launcher3.BuildConfig.IS_STUDIO_BUILD; +import static com.android.launcher3.states.RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Bundle; +import android.provider.Settings; +import android.text.TextUtils; +import android.view.MenuItem; +import android.view.View; + +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; +import androidx.core.view.WindowCompat; +import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; +import androidx.preference.Preference; +import androidx.preference.PreferenceCategory; +import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.PreferenceFragmentCompat.OnPreferenceStartFragmentCallback; +import androidx.preference.PreferenceFragmentCompat.OnPreferenceStartScreenCallback; +import androidx.preference.PreferenceGroup.PreferencePositionCallback; +import androidx.preference.PreferenceScreen; +import androidx.recyclerview.widget.RecyclerView; + +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherFiles; +import com.android.launcher3.LauncherPrefs; +import com.android.launcher3.R; +import com.android.launcher3.Utilities; +import com.android.launcher3.model.WidgetsModel; +import com.android.launcher3.states.RotationHelper; +import com.android.launcher3.util.DisplayController; +import com.android.launcher3.util.Executors; +import com.android.launcher3.util.SettingsCache; + +import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity; + +import com.android.systemui.shared.system.BlurUtils; + +import android.util.Log; +import java.util.Collections; +import java.util.List; + +public class SettingsMisc extends CollapsingToolbarBaseActivity + implements OnPreferenceStartFragmentCallback, OnPreferenceStartScreenCallback { + + @VisibleForTesting + static final String DEVELOPER_OPTIONS_KEY = "pref_developer_options"; + private static final String SUGGESTIONS_KEY = "pref_suggestions"; + + public static final String EXTRA_FRAGMENT_ARGS = ":settings:fragment_args"; + + // Intent extra to indicate the pref-key to highlighted when opening the settings activity + public static final String EXTRA_FRAGMENT_HIGHLIGHT_KEY = ":settings:fragment_args_key"; + // Intent extra to indicate the pref-key of the root screen when opening the settings activity + public static final String EXTRA_FRAGMENT_ROOT_KEY = ARG_PREFERENCE_ROOT; + public static final String EXTRA_FRAGMENT = ":settings:fragment"; + + private static final int DELAY_HIGHLIGHT_DURATION_MILLIS = 600; + public static final String SAVE_HIGHLIGHTED_KEY = "android:preference_highlighted"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.settings_activity); + + setActionBar(findViewById(R.id.action_bar)); + WindowCompat.setDecorFitsSystemWindows(getWindow(), false); + + Intent intent = getIntent(); + if (intent.hasExtra(EXTRA_FRAGMENT) || intent.hasExtra(EXTRA_FRAGMENT_ROOT_KEY) || intent.hasExtra(EXTRA_FRAGMENT_ARGS) + || intent.hasExtra(EXTRA_FRAGMENT_HIGHLIGHT_KEY)) { + getActionBar().setDisplayHomeAsUpEnabled(true); + } + + if (savedInstanceState == null) { + Bundle args = intent.getBundleExtra(EXTRA_FRAGMENT_ARGS); + if (args == null) { + args = new Bundle(); + } + + String highlight = intent.getStringExtra(EXTRA_FRAGMENT_HIGHLIGHT_KEY); + if (!TextUtils.isEmpty(highlight)) { + args.putString(EXTRA_FRAGMENT_HIGHLIGHT_KEY, highlight); + } + String root = intent.getStringExtra(EXTRA_FRAGMENT_ROOT_KEY); + if (!TextUtils.isEmpty(root)) { + args.putString(EXTRA_FRAGMENT_ROOT_KEY, root); + } + + final FragmentManager fm = getSupportFragmentManager(); + final Fragment f = fm.getFragmentFactory().instantiate(getClassLoader(), + getPreferenceFragment()); + f.setArguments(args); + // Display the fragment as the main content. + fm.beginTransaction().replace( + com.android.settingslib.collapsingtoolbar.R.id.content_frame, f).commit(); + } + LauncherPrefs.getPrefs(getApplicationContext()).registerOnSharedPreferenceChangeListener(this); + } + + /** + * Obtains the preference fragment to instantiate in this activity. + * + * @return the preference fragment class + * @throws IllegalArgumentException if the fragment is unknown to this activity + */ + private String getPreferenceFragment() { + String preferenceFragment = getIntent().getStringExtra(EXTRA_FRAGMENT); + String defaultFragment = getString(R.string.misc_settings_fragment_name); + + if (TextUtils.isEmpty(preferenceFragment)) { + return defaultFragment; + } else if (!preferenceFragment.equals(defaultFragment)) { + throw new IllegalArgumentException( + "Invalid fragment for this activity: " + preferenceFragment); + } else { + return preferenceFragment; + } + } + + private boolean startPreference(String fragment, Bundle args, String key) { + if (getSupportFragmentManager().isStateSaved()) { + // Sometimes onClick can come after onPause because of being posted on the handler. + // Skip starting new preferences in that case. + return false; + } + final FragmentManager fm = getSupportFragmentManager(); + final Fragment f = fm.getFragmentFactory().instantiate(getClassLoader(), fragment); + if (f instanceof DialogFragment) { + f.setArguments(args); + ((DialogFragment) f).show(fm, key); + } else { + startActivity(new Intent(this, SettingsMisc.class) + .putExtra(EXTRA_FRAGMENT, fragment) + .putExtra(EXTRA_FRAGMENT_ARGS, args)); + } + return true; + } + + @Override + public boolean onPreferenceStartFragment( + PreferenceFragmentCompat preferenceFragment, Preference pref) { + return startPreference(pref.getFragment(), pref.getExtras(), pref.getKey()); + } + + @Override + public boolean onPreferenceStartScreen(PreferenceFragmentCompat caller, PreferenceScreen pref) { + Bundle args = new Bundle(); + args.putString(ARG_PREFERENCE_ROOT, pref.getKey()); + return startPreference(getString(R.string.misc_category_title), args, pref.getKey()); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + onBackPressed(); + return true; + } + return super.onOptionsItemSelected(item); + } + + /** + * This fragment shows the launcher preferences. + */ + public static class MiscSettingsFragment extends PreferenceFragmentCompat implements + SettingsCache.OnChangeListener { + + protected boolean mDeveloperOptionsEnabled = false; + + private boolean mRestartOnResume = false; + + private String mHighLightKey; + private boolean mPreferenceHighlighted = false; + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + if (Utilities.IS_DEBUG_DEVICE) { + Uri devUri = Settings.Global.getUriFor(DEVELOPMENT_SETTINGS_ENABLED); + SettingsCache settingsCache = SettingsCache.INSTANCE.get(getContext()); + mDeveloperOptionsEnabled = settingsCache.getValue(devUri); + settingsCache.register(devUri, this); + } + super.onCreate(savedInstanceState); + } + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + final Bundle args = getArguments(); + mHighLightKey = args == null ? null : args.getString(EXTRA_FRAGMENT_HIGHLIGHT_KEY); + + if (savedInstanceState != null) { + mPreferenceHighlighted = savedInstanceState.getBoolean(SAVE_HIGHLIGHTED_KEY); + } + + getPreferenceManager().setSharedPreferencesName(LauncherFiles.SHARED_PREFERENCES_KEY); + setPreferencesFromResource(R.xml.launcher_misc_preferences, rootKey); + + PreferenceScreen screen = getPreferenceScreen(); + for (int i = screen.getPreferenceCount() - 1; i >= 0; i--) { + Preference preference = screen.getPreference(i); + if (!initPreference(preference)) { + screen.removePreference(preference); + } + } + + if (getActivity() != null && !TextUtils.isEmpty(getPreferenceScreen().getTitle())) { + getActivity().setTitle(getPreferenceScreen().getTitle()); + } + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + View listView = getListView(); + final int bottomPadding = listView.getPaddingBottom(); + listView.setOnApplyWindowInsetsListener((v, insets) -> { + v.setPadding( + v.getPaddingLeft(), + v.getPaddingTop(), + v.getPaddingRight(), + bottomPadding + insets.getSystemWindowInsetBottom()); + return insets.consumeSystemWindowInsets(); + }); + + // Overriding Text Direction in the Androidx preference library to support RTL + view.setTextDirection(View.TEXT_DIRECTION_LOCALE); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putBoolean(SAVE_HIGHLIGHTED_KEY, mPreferenceHighlighted); + } + + /** + * Initializes a preference. This is called for every preference. Returning false here + * will remove that preference from the list. + */ + protected boolean initPreference(Preference preference) { + switch (preference.getKey()) { + case ALLOW_ROTATION_PREFERENCE_KEY: + DisplayController.Info info = + DisplayController.INSTANCE.get(getContext()).getInfo(); + if (info.isTablet(info.realBounds)) { + // Launcher supports rotation by default. No need to show this setting. + return false; + } + // Initialize the UI once + preference.setDefaultValue(RotationHelper.getAllowRotationDefaultValue(info)); + return true; + + case DEVELOPER_OPTIONS_KEY: + if (IS_STUDIO_BUILD) { + preference.setOrder(0); + } + return mDeveloperOptionsEnabled; + } + + return true; + } + + @Override + public void onResume() { + super.onResume(); + + if (isAdded() && !mPreferenceHighlighted) { + PreferenceHighlighter highlighter = createHighlighter(); + if (highlighter != null) { + getView().postDelayed(highlighter, DELAY_HIGHLIGHT_DURATION_MILLIS); + mPreferenceHighlighted = true; + } + } + + if (mRestartOnResume) { + recreateActivityNow(); + } + } + + @Override + public void onSettingsChanged(boolean isEnabled) { + // Developer options changed, try recreate + tryRecreateActivity(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (Utilities.IS_DEBUG_DEVICE) { + SettingsCache.INSTANCE.get(getContext()) + .unregister(Settings.Global.getUriFor(DEVELOPMENT_SETTINGS_ENABLED), this); + } + } + + /** + * Tries to recreate the preference + */ + protected void tryRecreateActivity() { + if (isResumed()) { + recreateActivityNow(); + } else { + mRestartOnResume = true; + } + } + + private void recreateActivityNow() { + Activity activity = getActivity(); + if (activity != null) { + activity.recreate(); + } + } + + private PreferenceHighlighter createHighlighter() { + if (TextUtils.isEmpty(mHighLightKey)) { + return null; + } + + PreferenceScreen screen = getPreferenceScreen(); + if (screen == null) { + return null; + } + + RecyclerView list = getListView(); + PreferencePositionCallback callback = (PreferencePositionCallback) list.getAdapter(); + int position = callback.getPreferenceAdapterPosition(mHighLightKey); + return position >= 0 ? new PreferenceHighlighter( + list, position, screen.findPreference(mHighLightKey)) + : null; + } + } +} diff --git a/src/com/android/launcher3/settings/SettingsRecents.java b/src/com/android/launcher3/settings/SettingsRecents.java new file mode 100644 index 00000000000..69925ffbd73 --- /dev/null +++ b/src/com/android/launcher3/settings/SettingsRecents.java @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.launcher3.settings; + +import static androidx.preference.PreferenceFragmentCompat.ARG_PREFERENCE_ROOT; + +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.MenuItem; +import android.view.View; + +import androidx.core.view.WindowCompat; +import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.preference.Preference; +import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.PreferenceFragmentCompat.OnPreferenceStartFragmentCallback; +import androidx.preference.PreferenceFragmentCompat.OnPreferenceStartScreenCallback; +import androidx.preference.PreferenceGroup.PreferencePositionCallback; +import androidx.preference.PreferenceScreen; +import androidx.recyclerview.widget.RecyclerView; + +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherFiles; +import com.android.launcher3.LauncherPrefs; +import com.android.launcher3.R; +import com.android.launcher3.Utilities; + +import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity; + +public class SettingsRecents extends CollapsingToolbarBaseActivity + implements OnPreferenceStartFragmentCallback, OnPreferenceStartScreenCallback { + + public static final String EXTRA_FRAGMENT_ARGS = ":settings:fragment_args"; + + // Intent extra to indicate the pref-key to highlighted when opening the settings activity + public static final String EXTRA_FRAGMENT_HIGHLIGHT_KEY = ":settings:fragment_args_key"; + // Intent extra to indicate the pref-key of the root screen when opening the settings activity + public static final String EXTRA_FRAGMENT_ROOT_KEY = ARG_PREFERENCE_ROOT; + + private static final int DELAY_HIGHLIGHT_DURATION_MILLIS = 600; + public static final String SAVE_HIGHLIGHTED_KEY = "android:preference_highlighted"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.settings_activity); + + setActionBar(findViewById(R.id.action_bar)); + WindowCompat.setDecorFitsSystemWindows(getWindow(), false); + + Intent intent = getIntent(); + if (intent.hasExtra(EXTRA_FRAGMENT_ROOT_KEY) || intent.hasExtra(EXTRA_FRAGMENT_ARGS) + || intent.hasExtra(EXTRA_FRAGMENT_HIGHLIGHT_KEY)) { + getActionBar().setDisplayHomeAsUpEnabled(true); + } + + if (savedInstanceState == null) { + Bundle args = intent.getBundleExtra(EXTRA_FRAGMENT_ARGS); + if (args == null) { + args = new Bundle(); + } + + String highlight = intent.getStringExtra(EXTRA_FRAGMENT_HIGHLIGHT_KEY); + if (!TextUtils.isEmpty(highlight)) { + args.putString(EXTRA_FRAGMENT_HIGHLIGHT_KEY, highlight); + } + String root = intent.getStringExtra(EXTRA_FRAGMENT_ROOT_KEY); + if (!TextUtils.isEmpty(root)) { + args.putString(EXTRA_FRAGMENT_ROOT_KEY, root); + } + + final FragmentManager fm = getSupportFragmentManager(); + final Fragment f = fm.getFragmentFactory().instantiate(getClassLoader(), + getString(R.string.recents_settings_fragment_name)); + f.setArguments(args); + // Display the fragment as the main content. + fm.beginTransaction().replace( + com.android.settingslib.collapsingtoolbar.R.id.content_frame, f).commit(); + } + } + + private boolean startPreference(String fragment, Bundle args, String key) { + if (getSupportFragmentManager().isStateSaved()) { + // Sometimes onClick can come after onPause because of being posted on the handler. + // Skip starting new preferences in that case. + return false; + } + final FragmentManager fm = getSupportFragmentManager(); + final Fragment f = fm.getFragmentFactory().instantiate(getClassLoader(), fragment); + if (f instanceof DialogFragment) { + f.setArguments(args); + ((DialogFragment) f).show(fm, key); + } else { + startActivity(new Intent(this, SettingsRecents.class) + .putExtra(EXTRA_FRAGMENT_ARGS, args)); + } + return true; + } + + @Override + public boolean onPreferenceStartFragment( + PreferenceFragmentCompat preferenceFragment, Preference pref) { + return startPreference(pref.getFragment(), pref.getExtras(), pref.getKey()); + } + + @Override + public boolean onPreferenceStartScreen(PreferenceFragmentCompat caller, PreferenceScreen pref) { + Bundle args = new Bundle(); + args.putString(ARG_PREFERENCE_ROOT, pref.getKey()); + return startPreference(getString(R.string.recents_category_title), args, pref.getKey()); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + onBackPressed(); + return true; + } + return super.onOptionsItemSelected(item); + } + + /** + * This fragment shows the launcher preferences. + */ + public static class RecentsSettingsFragment extends PreferenceFragmentCompat { + + private String mHighLightKey; + private boolean mPreferenceHighlighted = false; + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + final Bundle args = getArguments(); + mHighLightKey = args == null ? null : args.getString(EXTRA_FRAGMENT_HIGHLIGHT_KEY); + + if (savedInstanceState != null) { + mPreferenceHighlighted = savedInstanceState.getBoolean(SAVE_HIGHLIGHTED_KEY); + } + + getPreferenceManager().setSharedPreferencesName(LauncherFiles.SHARED_PREFERENCES_KEY); + setPreferencesFromResource(R.xml.launcher_recents_preferences, rootKey); + + PreferenceScreen screen = getPreferenceScreen(); + for (int i = screen.getPreferenceCount() - 1; i >= 0; i--) { + Preference preference = screen.getPreference(i); + if (!initPreference(preference)) { + screen.removePreference(preference); + } + } + if (getActivity() != null && !TextUtils.isEmpty(getPreferenceScreen().getTitle())) { + getActivity().setTitle(getPreferenceScreen().getTitle()); + } + + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + View listView = getListView(); + final int bottomPadding = listView.getPaddingBottom(); + listView.setOnApplyWindowInsetsListener((v, insets) -> { + v.setPadding( + v.getPaddingLeft(), + v.getPaddingTop(), + v.getPaddingRight(), + bottomPadding + insets.getSystemWindowInsetBottom()); + return insets.consumeSystemWindowInsets(); + }); + + // Overriding Text Direction in the Androidx preference library to support RTL + view.setTextDirection(View.TEXT_DIRECTION_LOCALE); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putBoolean(SAVE_HIGHLIGHTED_KEY, mPreferenceHighlighted); + } + + /** + * Initializes a preference. This is called for every preference. Returning false here + * will remove that preference from the list. + */ + protected boolean initPreference(Preference preference) { + return true; + } + + @Override + public void onResume() { + super.onResume(); + + if (isAdded() && !mPreferenceHighlighted) { + PreferenceHighlighter highlighter = createHighlighter(); + if (highlighter != null) { + getView().postDelayed(highlighter, DELAY_HIGHLIGHT_DURATION_MILLIS); + mPreferenceHighlighted = true; + } + } + } + + private PreferenceHighlighter createHighlighter() { + if (TextUtils.isEmpty(mHighLightKey)) { + return null; + } + + PreferenceScreen screen = getPreferenceScreen(); + if (screen == null) { + return null; + } + + RecyclerView list = getListView(); + PreferencePositionCallback callback = (PreferencePositionCallback) list.getAdapter(); + int position = callback.getPreferenceAdapterPosition(mHighLightKey); + return position >= 0 ? new PreferenceHighlighter( + list, position, screen.findPreference(mHighLightKey)) + : null; + } + } +} diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java index 62eed5c5459..2a5f53dfe28 100644 --- a/src/com/android/launcher3/views/OptionsPopupView.java +++ b/src/com/android/launcher3/views/OptionsPopupView.java @@ -222,7 +222,7 @@ public static ArrayList getOptions(Launcher launcher) { OptionsPopupView::enterHomeGardening)); } options.add(new OptionItem(launcher, - R.string.settings_button_text, + R.string.settings_title, R.drawable.ic_setting, LAUNCHER_SETTINGS_BUTTON_TAP_OR_LONGPRESS, OptionsPopupView::startSettings)); From 8e84fe4d0b7aa0a5625c8bc18db1060ae08a2513 Mon Sep 17 00:00:00 2001 From: Alex Cruz Date: Fri, 19 Oct 2018 19:41:24 -0500 Subject: [PATCH 029/164] DerpLauncher: Change default icon Icon made by SwiftIcons https://www.swifticons.com/ Icon itself is covered by the Creative Commons license 3.0 https://creativecommons.org/licenses/by/3.0/us/ - No additional edits were made to the icons, all original. Change-Id: I7425d1e526ca6c613c1ee56d7871029f1b5f005a --- AndroidManifest-common.xml | 2 +- AndroidManifest.xml | 5 +++-- go/AndroidManifest-launcher.xml | 2 +- go/AndroidManifest.xml | 2 +- quickstep/AndroidManifest-launcher.xml | 2 +- quickstep/AndroidManifest.xml | 2 +- res/drawable/ic_launcher_home.xml | 21 ------------------ res/mipmap-hdpi/ic_launcher_home.png | Bin 0 -> 3912 bytes .../ic_launcher_home_foreground.png | Bin 236 -> 0 bytes res/mipmap-mdpi/ic_launcher_home.png | Bin 0 -> 2223 bytes .../ic_launcher_home_foreground.png | Bin 339 -> 0 bytes res/mipmap-xhdpi/ic_launcher_home.png | Bin 0 -> 5537 bytes .../ic_launcher_home_foreground.png | Bin 357 -> 0 bytes res/mipmap-xxhdpi/ic_launcher_home.png | Bin 0 -> 10039 bytes .../ic_launcher_home_foreground.png | Bin 485 -> 0 bytes res/mipmap-xxxhdpi/ic_launcher_home.png | Bin 0 -> 16807 bytes 16 files changed, 8 insertions(+), 28 deletions(-) delete mode 100644 res/drawable/ic_launcher_home.xml create mode 100644 res/mipmap-hdpi/ic_launcher_home.png delete mode 100644 res/mipmap-hdpi/ic_launcher_home_foreground.png create mode 100644 res/mipmap-mdpi/ic_launcher_home.png delete mode 100644 res/mipmap-mdpi/ic_launcher_home_foreground.png create mode 100644 res/mipmap-xhdpi/ic_launcher_home.png delete mode 100644 res/mipmap-xhdpi/ic_launcher_home_foreground.png create mode 100644 res/mipmap-xxhdpi/ic_launcher_home.png delete mode 100644 res/mipmap-xxhdpi/ic_launcher_home_foreground.png create mode 100644 res/mipmap-xxxhdpi/ic_launcher_home.png diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml index 484a5e617e4..a0ad7411f00 100644 --- a/AndroidManifest-common.xml +++ b/AndroidManifest-common.xml @@ -74,7 +74,7 @@ android:backupInForeground="true" android:fullBackupContent="@xml/backupscheme" android:hardwareAccelerated="true" - android:icon="@drawable/ic_launcher_home" + android:icon="@mipmap/ic_launcher_home" android:label="@string/derived_app_name" android:largeHeap="@bool/config_largeHeap" android:restoreAnyVersion="true" diff --git a/AndroidManifest.xml b/AndroidManifest.xml index e5b6b64a18d..a68ba6b6d4e 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -33,13 +33,14 @@ android:fullBackupContent="@xml/backupscheme" android:hardwareAccelerated="true" android:debuggable="true" - android:icon="@drawable/ic_launcher_home" + android:icon="@mipmap/ic_launcher_home" android:label="@string/derived_app_name" android:theme="@style/AppTheme" android:largeHeap="@bool/config_largeHeap" android:restoreAnyVersion="true" android:supportsRtl="true" - tools:ignore="GoogleAppIndexingWarning"> + tools:ignore="GoogleAppIndexingWarning" + tools:replace="android:icon"> - - - - - - diff --git a/res/mipmap-hdpi/ic_launcher_home.png b/res/mipmap-hdpi/ic_launcher_home.png new file mode 100644 index 0000000000000000000000000000000000000000..ebed06a10fd586a75739c8de29e2bf597962b88a GIT binary patch literal 3912 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 literal 0 HcmV?d00001 diff --git a/res/mipmap-hdpi/ic_launcher_home_foreground.png b/res/mipmap-hdpi/ic_launcher_home_foreground.png deleted file mode 100644 index d068d92361a06550fb1bcdf36fbc4bf56242d54e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 236 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~M1W6-E06|){rmU-|Ns9C14G(O z28NkujJG~Lkd;*dlwd3g@(X5gcy=QV$Z7I)aSW-r_4dL>z6Jx1mc(q=`~Q1QL!@ST zvx^@#{d2kXq4bSSI^01QuQhjd%Q~fAzm?V=urg{pU$2PM(daz_S{a5;E6(U}afk}8 z47;BZ=ab}J3zCCNews?D5gxej-a_Kuo17Rft1vqit#&7!y*N{WWmyWyB_hz=QCtur6nh;&;+*lHbj|CeQ+mYp5j;7W@=uD0~q9N_d8)tXv`J+MsP{sRun;ca9!53<>uqZ=V z^L{^$q|PXWH+uBgVXAA zfGx$L0f;89UUYR5s`we1p%9IgVoQ-F&Q}}&o~`!JiRd;59F(G*FA_f`zx^1 zc045ChLzI$7+D#B4g>UW)@0j;dI^Akrs*-D%1SQS)1lv978<}e@}ui!oOovhMXPfV z7bo*8g`Z`(ZpMeQ+nwm{xrGK6Kqx7&7J$C(9s#(*FaVcEP*lVL;N|(C7zuIDW_O~8 z10WPrGX}`t)1iNqxKN2EU@KlUOallfJTHiSf_ec4(6BLsaiQ1&Jk_Cpv@8jm!vrw_ zIL=x?sgO;3xsdB{-DK7PmazcgvXB=*hm_=ah{fVy0LB`efaXZeOLluqqaPW1MEjfO|OStw=}Sn{M+zk{(rcz|P(L5-XGR~J+kTHUk%CFM12C$d~*d|~BA_z&NBnt&ufFmxyD1~Y< zY&Iu){z)uAdLeb}T!;ZEOTxA_92X)Ik)Dl}tn<1V#{>X;!pmVnb^LSawC}`#YjvPs zV$TQwaiM*cF$TzcLaVPM0K@_up}8s|LCjd7cpj8&Gso4s9A-4AtFT1Y35!RAqvP$k z?OGL7@O%J!E7P$)mKMmX*Xrw{hygADS9l5RXjE@PuCxcOmLqsrc>+qxh(o5!7<8}j z>%kB3NIKRR#L$Hnu>e9bKqTN=fZI-!dm7Oo4rx|n+>?eEj2~cod=o0--oR_-llZ{? zbARpdyU@1*@S)Fz*et{^UdyEKmOR=+a}3%uMujN;xZGb@hSdX`Z!){ABIdS_I}j+yE^_U+qm%?JJuo&hdcHF z3xBB{-MKD_s%8Nw#}pQwI>-o5Ih`=AC`Ip2e}Ol<#+dH`p>M%y)tCoKE=3{=wQDs< zR&g3ao&`xadis3>J$Ak(C-SNU5;P0>1gS-yDM{$TIuhGlQ7YU27g`-TEAW$w&Yq`NFci^vaVRIT;D* zhj-+JU0#oYjDk~4*xdL{%OGyu9UsyEt$u@J=;O};xFP|N`|+9$2R5q;YF^7pi&v1P zKd&YJe+SWg^TlD@)=f@LTs^zXtUdTw0MoXcgm!311msP;r7VLwoHOFqaZi& z{)We-$%}t1lB*T~A_=I#CLdq8dxBu5b-U>)^MF(T#pQ{Q|L}%W*LM?uk?%U;vJl_J z$bwA*^OGv$Az>1B#NExAXr1#c4VT#kr_h$ocF6c*`Pj x6%wpL+ex96GFyUtLj%lw*!KW4*I8^w{0|Jf)NN1<5S9P{002ovPDHLkV1lil8}_^mIV0)GdMiEkp|)RiyD=97dKdZ~+#mp}YjODMbT4y&m-1Kwk zs;o4_{A;D|dvy4tqi=NS2y8yS;Y@!)q~)2mO5QNB!)BWM?kz8p3ozsHewR|Vqvi99 zJ*y)3gs%Oy>dfZZyT9F>U0J$W<9V9(*;6@h?yX8czb!Fslh0HA_L)b`((b3|JEXd} dxa==vU$tP>xMf?fas diff --git a/res/mipmap-xhdpi/ic_launcher_home.png b/res/mipmap-xhdpi/ic_launcher_home.png new file mode 100644 index 0000000000000000000000000000000000000000..4cacae40c70769c73a92c306996cac07cc837285 GIT binary patch literal 5537 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 literal 0 HcmV?d00001 diff --git a/res/mipmap-xhdpi/ic_launcher_home_foreground.png b/res/mipmap-xhdpi/ic_launcher_home_foreground.png deleted file mode 100644 index 7a9daf5bfe7a5fcfdf7e772dfe5300373d287389..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 357 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 N002ovPDHLkV1jre>iGZw literal 0 HcmV?d00001 diff --git a/res/mipmap-xxhdpi/ic_launcher_home_foreground.png b/res/mipmap-xxhdpi/ic_launcher_home_foreground.png deleted file mode 100644 index 03b493e4a3513a3c688698348ddd64180bdfe33d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 485 zcmeAS@N?(olHy`uVBq!ia0y~yU~~at7G|Kx+9Oe4fs{mmPl#(`0g%P8fB*jf|Noz1 zU`U(Ez%cWS@z$sFC1#WWB^XPB{DK)Ap4~_Tagw~Fdh=keOM~z{;U~;(nkWH%}MGkcwMx?>J^PJ213eWT|Rc;>$1K&40mb z)44_F8kUX<;wKhe&*wh3KyqtSr{BZ9OS$TH%ZtY70L?=J5*a(!tx@rsq7nGW-XlgG z%u3qVSr{VMeadY6%!wL-i(EQ&7Yn`WGRin}=CJ!y1(1Nyb8jE_r%U&I6I*xF1E_b= zk(t8PZmOdC)4=LKtMExq-Bg_xCZq~9x$x4FV=MN^)tgwAot)SQH8NPGtmo9mcg9=Z zoWJfTe5MCzrm9zt<#~t?uJ7bNI^lK%s3qdvm-8H)=NY)XoC+**TXC#j^Ff{zEVRl>T U{kpq~Z7)c|)78&qol`;+0B9eraR2}S diff --git a/res/mipmap-xxxhdpi/ic_launcher_home.png b/res/mipmap-xxxhdpi/ic_launcher_home.png new file mode 100644 index 0000000000000000000000000000000000000000..b7ed7b39446debf56d205c7d53b82a850a653fd6 GIT binary patch literal 16807 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 Date: Sat, 12 Dec 2020 19:05:59 -0800 Subject: [PATCH 030/164] DerpLauncher: Reduce app label text size The default 13-point label size can barely fit any app names on modern phone form factors without ellipsizing. Reducing the size to 12 points allows us to fit most apps names, and upon visual inspection, it appears to be the same size as that of Pixel Launcher. Change-Id: I6ad63c14237f1f38c86ec02059b03896e5dd3a77 --- res/xml/device_profiles.xml | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/res/xml/device_profiles.xml b/res/xml/device_profiles.xml index 8c996b88400..2958af1542a 100644 --- a/res/xml/device_profiles.xml +++ b/res/xml/device_profiles.xml @@ -33,7 +33,7 @@ launcher:minWidthDps="200" launcher:minHeightDps="200" launcher:iconImageSize="48" - launcher:iconTextSize="13.0" + launcher:iconTextSize="12.0" launcher:allAppsBorderSpace="16" launcher:allAppsCellHeight="104" launcher:canBeDefault="true" /> @@ -43,7 +43,7 @@ launcher:minWidthDps="200" launcher:minHeightDps="300" launcher:iconImageSize="48" - launcher:iconTextSize="13.0" + launcher:iconTextSize="12.0" launcher:allAppsBorderSpace="16" launcher:allAppsCellHeight="104" launcher:canBeDefault="true" /> @@ -66,7 +66,7 @@ launcher:minWidthDps="255" launcher:minHeightDps="300" launcher:iconImageSize="48" - launcher:iconTextSize="13.0" + launcher:iconTextSize="12.0" launcher:allAppsBorderSpace="16" launcher:allAppsCellHeight="104" launcher:canBeDefault="true" /> @@ -76,7 +76,7 @@ launcher:minWidthDps="255" launcher:minHeightDps="400" launcher:iconImageSize="48" - launcher:iconTextSize="13.0" + launcher:iconTextSize="12.0" launcher:allAppsBorderSpace="16" launcher:allAppsCellHeight="104" launcher:canBeDefault="true" /> @@ -101,7 +101,7 @@ launcher:minWidthDps="275" launcher:minHeightDps="420" launcher:iconImageSize="46" - launcher:iconTextSize="13.0" + launcher:iconTextSize="12.0" launcher:allAppsBorderSpace="16" launcher:allAppsCellHeight="104" launcher:canBeDefault="true" /> @@ -111,7 +111,7 @@ launcher:minWidthDps="255" launcher:minHeightDps="450" launcher:iconImageSize="46" - launcher:iconTextSize="13.0" + launcher:iconTextSize="12.0" launcher:allAppsBorderSpace="16" launcher:allAppsCellHeight="104" launcher:canBeDefault="true" /> @@ -121,7 +121,7 @@ launcher:minWidthDps="296" launcher:minHeightDps="491.33" launcher:iconImageSize="46" - launcher:iconTextSize="13.0" + launcher:iconTextSize="12.0" launcher:allAppsBorderSpace="16" launcher:allAppsCellHeight="104" launcher:canBeDefault="true" /> @@ -131,7 +131,7 @@ launcher:minWidthDps="359" launcher:minHeightDps="567" launcher:iconImageSize="50" - launcher:iconTextSize="13.0" + launcher:iconTextSize="12.0" launcher:allAppsBorderSpace="16" launcher:allAppsCellHeight="104" launcher:canBeDefault="true" /> @@ -141,7 +141,7 @@ launcher:minWidthDps="335" launcher:minHeightDps="567" launcher:iconImageSize="50" - launcher:iconTextSize="13.0" + launcher:iconTextSize="12.0" launcher:allAppsBorderSpace="16" launcher:allAppsCellHeight="104" launcher:canBeDefault="true" /> @@ -166,7 +166,7 @@ launcher:minWidthDps="406" launcher:minHeightDps="694" launcher:iconImageSize="56" - launcher:iconTextSize="14.4" + launcher:iconTextSize="12.0" launcher:allAppsBorderSpace="16" launcher:allAppsCellHeight="104" launcher:canBeDefault="true" /> @@ -176,7 +176,7 @@ launcher:minWidthDps="406" launcher:minHeightDps="694" launcher:iconImageSize="56" - launcher:iconTextSize="14.4" + launcher:iconTextSize="12.0" launcher:allAppsBorderSpace="16" launcher:allAppsCellHeight="104" launcher:canBeDefault="true" /> @@ -186,7 +186,7 @@ launcher:minWidthDps="255" launcher:minHeightDps="400" launcher:iconImageSize="48" - launcher:iconTextSize="13.0" + launcher:iconTextSize="12.0" launcher:allAppsBorderSpace="16" launcher:allAppsCellHeight="104" launcher:canBeDefault="true" /> @@ -209,7 +209,7 @@ launcher:minWidthDps="406" launcher:minHeightDps="694" launcher:iconImageSize="56" - launcher:iconTextSize="13.0" + launcher:iconTextSize="12.0" launcher:allAppsBorderSpace="16" launcher:allAppsCellHeight="104" launcher:canBeDefault="true" /> @@ -232,7 +232,7 @@ launcher:minWidthDps="406" launcher:minHeightDps="694" launcher:iconImageSize="56" - launcher:iconTextSize="13.0" + launcher:iconTextSize="12.0" launcher:allAppsBorderSpace="16" launcher:allAppsCellHeight="104" launcher:canBeDefault="true" /> @@ -302,7 +302,7 @@ launcher:minWidthDps="406" launcher:minHeightDps="694" launcher:iconImageSize="48" - launcher:iconTextSize="13.0" + launcher:iconTextSize="12.0" launcher:allAppsBorderSpace="16" launcher:allAppsCellHeight="104" launcher:canBeDefault="true" /> From ea61712bb20baea8f1c2d3cf24391d5d849870f5 Mon Sep 17 00:00:00 2001 From: daniml3 Date: Sun, 7 Mar 2021 21:03:20 +0100 Subject: [PATCH 031/164] DerpLauncher: Adjust the icon size to the grid size [ghostrider-reborn: also adjust text sizes] - Hotseats for 4_by_5 is 4 - Keep camera in hotseat and remove contacts. Co-authored-by: Adithya R Change-Id: I02ff29cc14e5d4288a34dbd8c4658f7cea7d579f Signed-off-by: althafvly --- res/xml/default_workspace_4x5.xml | 16 +++------- res/xml/device_profiles.xml | 52 ++++++++++++++++++------------- 2 files changed, 35 insertions(+), 33 deletions(-) diff --git a/res/xml/default_workspace_4x5.xml b/res/xml/default_workspace_4x5.xml index 58eb389333c..6c92506caa4 100644 --- a/res/xml/default_workspace_4x5.xml +++ b/res/xml/default_workspace_4x5.xml @@ -51,18 +51,10 @@ - - - - @@ -70,8 +62,8 @@ diff --git a/res/xml/device_profiles.xml b/res/xml/device_profiles.xml index 2958af1542a..bc6f49658e0 100644 --- a/res/xml/device_profiles.xml +++ b/res/xml/device_profiles.xml @@ -21,6 +21,7 @@ launcher:name="2_by_2" launcher:numRows="2" launcher:numColumns="2" + launcher:numAllAppsColumns="4" launcher:numFolderRows="2" launcher:numFolderColumns="2" launcher:numHotseatIcons="2" @@ -32,8 +33,10 @@ launcher:name="Super Short Stubby" launcher:minWidthDps="200" launcher:minHeightDps="200" - launcher:iconImageSize="48" - launcher:iconTextSize="12.0" + launcher:iconImageSize="120" + launcher:iconTextSize="17.0" + launcher:allAppsIconSize="60.0" + launcher:allAppsIconTextSize="14.0" launcher:allAppsBorderSpace="16" launcher:allAppsCellHeight="104" launcher:canBeDefault="true" /> @@ -42,8 +45,10 @@ launcher:name="Shorter Stubby" launcher:minWidthDps="200" launcher:minHeightDps="300" - launcher:iconImageSize="48" - launcher:iconTextSize="12.0" + launcher:iconImageSize="120" + launcher:iconTextSize="17.0" + launcher:allAppsIconSize="60" + launcher:allAppsIconTextSize="14.0" launcher:allAppsBorderSpace="16" launcher:allAppsCellHeight="104" launcher:canBeDefault="true" /> @@ -54,6 +59,7 @@ launcher:name="3_by_3" launcher:numRows="3" launcher:numColumns="3" + launcher:numAllAppsColumns="4" launcher:numFolderRows="2" launcher:numFolderColumns="3" launcher:numHotseatIcons="3" @@ -65,8 +71,10 @@ launcher:name="Super Short Stubby" launcher:minWidthDps="255" launcher:minHeightDps="300" - launcher:iconImageSize="48" - launcher:iconTextSize="12.0" + launcher:iconImageSize="85" + launcher:iconTextSize="15.0" + launcher:allAppsIconSize="60" + launcher:allAppsIconTextSize="14.0" launcher:allAppsBorderSpace="16" launcher:allAppsCellHeight="104" launcher:canBeDefault="true" /> @@ -75,8 +83,10 @@ launcher:name="Shorter Stubby" launcher:minWidthDps="255" launcher:minHeightDps="400" - launcher:iconImageSize="48" - launcher:iconTextSize="12.0" + launcher:iconImageSize="85" + launcher:iconTextSize="15.0" + launcher:allAppsIconSize="60" + launcher:allAppsIconTextSize="14.0" launcher:allAppsBorderSpace="16" launcher:allAppsCellHeight="104" launcher:canBeDefault="true" /> @@ -87,9 +97,9 @@ launcher:name="4_by_5" launcher:numRows="5" launcher:numColumns="4" - launcher:numFolderRows="4" - launcher:numFolderColumns="4" - launcher:numHotseatIcons="5" + launcher:numFolderRows="3" + launcher:numFolderColumns="3" + launcher:numHotseatIcons="4" launcher:numExtendedHotseatIcons="6" launcher:dbFile="launcher_4_by_5.db" launcher:inlineNavButtonsEndSpacing="@dimen/taskbar_button_margin_split" @@ -100,8 +110,8 @@ launcher:name="Short Stubby" launcher:minWidthDps="275" launcher:minHeightDps="420" - launcher:iconImageSize="46" - launcher:iconTextSize="12.0" + launcher:iconImageSize="65" + launcher:iconTextSize="13.0" launcher:allAppsBorderSpace="16" launcher:allAppsCellHeight="104" launcher:canBeDefault="true" /> @@ -110,8 +120,8 @@ launcher:name="Stubby" launcher:minWidthDps="255" launcher:minHeightDps="450" - launcher:iconImageSize="46" - launcher:iconTextSize="12.0" + launcher:iconImageSize="65" + launcher:iconTextSize="13.0" launcher:allAppsBorderSpace="16" launcher:allAppsCellHeight="104" launcher:canBeDefault="true" /> @@ -120,8 +130,8 @@ launcher:name="Nexus S" launcher:minWidthDps="296" launcher:minHeightDps="491.33" - launcher:iconImageSize="46" - launcher:iconTextSize="12.0" + launcher:iconImageSize="65" + launcher:iconTextSize="13.0" launcher:allAppsBorderSpace="16" launcher:allAppsCellHeight="104" launcher:canBeDefault="true" /> @@ -130,8 +140,8 @@ launcher:name="Nexus 4" launcher:minWidthDps="359" launcher:minHeightDps="567" - launcher:iconImageSize="50" - launcher:iconTextSize="12.0" + launcher:iconImageSize="65" + launcher:iconTextSize="13.0" launcher:allAppsBorderSpace="16" launcher:allAppsCellHeight="104" launcher:canBeDefault="true" /> @@ -140,8 +150,8 @@ launcher:name="Nexus 5" launcher:minWidthDps="335" launcher:minHeightDps="567" - launcher:iconImageSize="50" - launcher:iconTextSize="12.0" + launcher:iconImageSize="65" + launcher:iconTextSize="13.0" launcher:allAppsBorderSpace="16" launcher:allAppsCellHeight="104" launcher:canBeDefault="true" /> From 5d2035b5d804be7c61e5de6fdced975651831d00 Mon Sep 17 00:00:00 2001 From: Nebojsa Cvetkovic Date: Fri, 10 Nov 2017 16:20:37 +0100 Subject: [PATCH 032/164] DerpLauncher: Workspace: Allow resizing any widget [BadDaemon: Adapt for S] Change-Id: Iba122eb45d4ba81e53267ff341addfe281cf02fe Signed-off-by: Joey Rizzoli --- .../launcher3/AppWidgetResizeFrame.java | 28 +++---------------- src/com/android/launcher3/Workspace.java | 2 +- 2 files changed, 5 insertions(+), 25 deletions(-) diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java index b51e850c04e..90faf0d171b 100644 --- a/src/com/android/launcher3/AppWidgetResizeFrame.java +++ b/src/com/android/launcher3/AppWidgetResizeFrame.java @@ -15,7 +15,6 @@ import android.animation.LayoutTransition; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; -import android.appwidget.AppWidgetProviderInfo; import android.content.Context; import android.graphics.Rect; import android.graphics.drawable.Drawable; @@ -248,23 +247,6 @@ private void setupForWidget(LauncherAppWidgetHostView widgetView, CellLayout cel mMaxHSpan = info.maxSpanX; mMaxVSpan = info.maxSpanY; - // Only show resize handles for the directions in which resizing is possible. - InvariantDeviceProfile idp = LauncherAppState.getIDP(cellLayout.getContext()); - mVerticalResizeActive = (info.resizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0 - && mMinVSpan < idp.numRows && mMaxVSpan > 1 - && mMinVSpan < mMaxVSpan; - if (!mVerticalResizeActive) { - mDragHandles[INDEX_TOP].setVisibility(GONE); - mDragHandles[INDEX_BOTTOM].setVisibility(GONE); - } - mHorizontalResizeActive = (info.resizeMode & AppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0 - && mMinHSpan < idp.numColumns && mMaxHSpan > 1 - && mMinHSpan < mMaxHSpan; - if (!mHorizontalResizeActive) { - mDragHandles[INDEX_LEFT].setVisibility(GONE); - mDragHandles[INDEX_RIGHT].setVisibility(GONE); - } - mReconfigureButton = (ImageButton) findViewById(R.id.widget_reconfigure_button); if (info.isReconfigurable()) { mReconfigureButton.setVisibility(VISIBLE); @@ -330,12 +312,10 @@ private void setupForWidget(LauncherAppWidgetHostView widgetView, CellLayout cel } public boolean beginResizeIfPointInRegion(int x, int y) { - mLeftBorderActive = (x < mTouchTargetWidth) && mHorizontalResizeActive; - mRightBorderActive = (x > getWidth() - mTouchTargetWidth) && mHorizontalResizeActive; - mTopBorderActive = (y < mTouchTargetWidth + mTopTouchRegionAdjustment) - && mVerticalResizeActive; - mBottomBorderActive = (y > getHeight() - mTouchTargetWidth + mBottomTouchRegionAdjustment) - && mVerticalResizeActive; + mLeftBorderActive = x < mTouchTargetWidth; + mRightBorderActive = x > getWidth() - mTouchTargetWidth; + mTopBorderActive = y < mTouchTargetWidth + mTopTouchRegionAdjustment; + mBottomBorderActive = y > getHeight() - mTouchTargetWidth + mBottomTouchRegionAdjustment; boolean anyBordersActive = mLeftBorderActive || mRightBorderActive || mTopBorderActive || mBottomBorderActive; diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index e601a3e2985..9808592786b 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -2224,7 +2224,7 @@ public void onDrop(final DragObject d, DragOptions options) { private Runnable getWidgetResizeFrameRunnable(DragOptions options, LauncherAppWidgetHostView hostView, CellLayout cellLayout) { AppWidgetProviderInfo pInfo = hostView.getAppWidgetInfo(); - if (pInfo != null && pInfo.resizeMode != AppWidgetProviderInfo.RESIZE_NONE) { + if (pInfo != null) { return () -> { if (!isPageInTransition()) { AppWidgetResizeFrame.showForWidget(hostView, cellLayout); From b906b2257335bc1058f48fce183d6b68b03b5649 Mon Sep 17 00:00:00 2001 From: Joey Date: Sun, 4 Feb 2018 11:36:32 +0100 Subject: [PATCH 033/164] DerpLauncher: Allow disabling workspace edit Co-authored-by: Michael W Co-authored-by: Han Wang <416810799@qq.com> Change-Id: I503e19cbc512eac0e4a8c8bccc16a6ccc0e805da --- res/values-de/derp_strings.xml | 6 ++++++ res/values/derp_strings.xml | 6 ++++++ res/xml/launcher_home_screen_preferences.xml | 9 +++++++++ src/com/android/launcher3/InvariantDeviceProfile.java | 2 ++ src/com/android/launcher3/Utilities.java | 6 ++++++ src/com/android/launcher3/dragndrop/DragController.java | 6 ++++++ .../android/launcher3/popup/PopupContainerWithArrow.java | 4 ++++ src/com/android/launcher3/popup/SystemShortcut.java | 1 + src/com/android/launcher3/views/OptionsPopupView.java | 2 +- .../launcher3/widget/LauncherAppWidgetHostView.java | 2 ++ 10 files changed, 43 insertions(+), 1 deletion(-) diff --git a/res/values-de/derp_strings.xml b/res/values-de/derp_strings.xml index 36ce176887d..0707c8792fb 100644 --- a/res/values-de/derp_strings.xml +++ b/res/values-de/derp_strings.xml @@ -25,4 +25,10 @@ Entwickler-Optionen Einige versteckte Funktionen auf eigene Gefahr aktivieren + + + Layout sperren + Symbole und Widgets können nicht auf dem Startbildschirm hinzugefügt, entfernt und verschoben werden + Symbole und Widgets können auf dem Startbildschirm hinzugefügt, entfernt und verschoben werden + Es ist nicht möglich, Widgets zum Startbildschirm hinzuzufügen diff --git a/res/values/derp_strings.xml b/res/values/derp_strings.xml index 9d807490aca..7c91a47996a 100644 --- a/res/values/derp_strings.xml +++ b/res/values/derp_strings.xml @@ -31,4 +31,10 @@ Developer options Enable some hidden features at your own risk + + + Lock layout + Icons and widgets can\'t be added, removed and moved on the homescreen + Icons and widgets can be added, removed and moved on the homescreen + It\'s not possible to add widgets to the home screen diff --git a/res/xml/launcher_home_screen_preferences.xml b/res/xml/launcher_home_screen_preferences.xml index 05a5a8c74d3..5a5d428958c 100644 --- a/res/xml/launcher_home_screen_preferences.xml +++ b/res/xml/launcher_home_screen_preferences.xml @@ -22,6 +22,15 @@ + + T findViewByPredicate(@NonNull View root, } return null; } + + public static boolean isWorkspaceEditAllowed(Context context) { + SharedPreferences prefs = LauncherPrefs.getPrefs(context.getApplicationContext()); + return !prefs.getBoolean(InvariantDeviceProfile.KEY_WORKSPACE_LOCK, false); + } } diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java index bc5a164da8d..ff902e0817e 100644 --- a/src/com/android/launcher3/dragndrop/DragController.java +++ b/src/com/android/launcher3/dragndrop/DragController.java @@ -32,6 +32,7 @@ import com.android.launcher3.DragSource; import com.android.launcher3.DropTarget; import com.android.launcher3.Flags; +import com.android.launcher3.Utilities; import com.android.launcher3.logging.InstanceId; import com.android.launcher3.model.data.AppPairInfo; import com.android.launcher3.model.data.ItemInfo; @@ -407,6 +408,11 @@ public boolean onControllerInterceptTouchEvent(MotionEvent ev) { return false; } + if (!Utilities.isWorkspaceEditAllowed(mActivity.getDragLayer().getContext())) { + cancelDrag(); + return false; + } + Point dragLayerPos = getClampedDragLayerPos(getX(ev), getY(ev)); mLastTouch.set(dragLayerPos.x, dragLayerPos.y); if (ev.getAction() == MotionEvent.ACTION_DOWN) { diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java index 1c9db17822f..53824999707 100644 --- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java +++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java @@ -48,6 +48,7 @@ import com.android.launcher3.Flags; import com.android.launcher3.Launcher; import com.android.launcher3.R; +import com.android.launcher3.Utilities; import com.android.launcher3.accessibility.LauncherAccessibilityDelegate; import com.android.launcher3.accessibility.ShortcutMenuAccessibilityDelegate; import com.android.launcher3.dragndrop.DragController; @@ -625,6 +626,9 @@ public boolean onLongClick(View v) { // Return early if not the correct view if (!(v.getParent() instanceof DeepShortcutView)) return false; + // Return early if workspace edit is disabled + if (!Utilities.isWorkspaceEditAllowed(mLauncher.getApplicationContext())) return false; + // Long clicked on a shortcut. DeepShortcutView sv = (DeepShortcutView) v.getParent(); sv.setWillDrawIcon(false); diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java index 83e98100609..70fe680ba78 100644 --- a/src/com/android/launcher3/popup/SystemShortcut.java +++ b/src/com/android/launcher3/popup/SystemShortcut.java @@ -125,6 +125,7 @@ public Widgets(T target, ItemInfo itemInfo, @NonNull View originalView) { @Override public void onClick(View view) { + if (!Utilities.isWorkspaceEditAllowed((Context) mTarget)) return; AbstractFloatingView.closeAllOpenViews(mTarget); WidgetsBottomSheet widgetsBottomSheet = (WidgetsBottomSheet) mTarget.getLayoutInflater().inflate( diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java index 2a5f53dfe28..74cf5aa1ccf 100644 --- a/src/com/android/launcher3/views/OptionsPopupView.java +++ b/src/com/android/launcher3/views/OptionsPopupView.java @@ -207,7 +207,7 @@ public static ArrayList getOptions(Launcher launcher) { R.drawable.ic_palette, IGNORE, OptionsPopupView::startWallpaperPicker)); - if (WIDGETS_ENABLED) { + if (WIDGETS_ENABLED && Utilities.isWorkspaceEditAllowed(launcher)) { options.add(new OptionItem(launcher, R.string.widget_button_text, R.drawable.ic_widget, diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java index 44ab966472c..c42b6722179 100644 --- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java +++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java @@ -41,6 +41,7 @@ import com.android.launcher3.CheckLongPressHelper; import com.android.launcher3.Flags; import com.android.launcher3.R; +import com.android.launcher3.Utilities; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.util.Themes; import com.android.launcher3.views.ActivityContext; @@ -111,6 +112,7 @@ public void setColorResources(@Nullable SparseIntArray colors) { @Override public boolean onLongClick(View view) { + if (!Utilities.isWorkspaceEditAllowed((Context) mActivityContext)) return true; if (mIsScrollable) { mActivityContext.getDragLayer().requestDisallowInterceptTouchEvent(false); } From abdde45e9f4120372ec6a64f6b8d54fe64a2fddd Mon Sep 17 00:00:00 2001 From: Arne Coucheron Date: Wed, 28 Jun 2017 02:20:46 +0200 Subject: [PATCH 034/164] DerpLauncher: Disable QSB on first screen by default Change-Id: I24f1682cbad10610f04f7b8ada238b43addd23da --- src_build_config/com/android/launcher3/BuildConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src_build_config/com/android/launcher3/BuildConfig.java b/src_build_config/com/android/launcher3/BuildConfig.java index 6d4f56d655b..2630ec130f6 100644 --- a/src_build_config/com/android/launcher3/BuildConfig.java +++ b/src_build_config/com/android/launcher3/BuildConfig.java @@ -24,7 +24,7 @@ public final class BuildConfig { * Flag to state if the QSB is on the first screen and placed on the top, * this can be overwritten in other launchers with a different value, if needed. */ - public static final boolean QSB_ON_FIRST_SCREEN = true; + public static final boolean QSB_ON_FIRST_SCREEN = false; /** * Flag to state if the widget on the top of the first screen should be shown. From 3d0162e9317a2960756237a20408153833c10f65 Mon Sep 17 00:00:00 2001 From: nift4 Date: Fri, 21 Apr 2023 18:26:23 +0200 Subject: [PATCH 035/164] DerpLauncher: Let's keep 2-button nav alive for a little longer * Refactor to avoid breaking gesture nav This partially reverts commit 9cddf4133befc721f2eb6a374b40fbb1b74f64ef. This partially reverts commit 0130252c00ef268dfb80d9bff9c3da90bfffd7ff. Change-Id: I1823de2a911f8a17c3716bc0b1b8e6c9c55d37cd --- .../android/quickstep/AbsSwipeUpHandler.java | 29 +++++++++++++++++++ .../RecentsAnimationDeviceState.java | 8 +++++ .../OtherActivityInputConsumer.java | 20 +++++++++++++ 3 files changed, 57 insertions(+) diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index 1acafab217b..ba64a321f11 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -310,6 +310,7 @@ private static int getNextStateFlag(String name) { private boolean mWasLauncherAlreadyVisible; + private boolean mPassedOverviewThreshold; private boolean mGestureStarted; private boolean mLogDirectionUpOrLeft = true; private boolean mIsLikelyToStartNewTask; @@ -898,6 +899,14 @@ public Intent getLaunchIntent() { @UiThread @Override public void onCurrentShiftUpdated() { + final boolean passed = hasReachedHomeOverviewThreshold(); + if (passed != mPassedOverviewThreshold) { + mPassedOverviewThreshold = passed; + if (mDeviceState.isTwoButtonNavMode() && !mGestureState.isHandlingAtomicEvent()) { + performHapticFeedback(); + } + } + float threshold = DeviceConfigWrapper.get().getAllAppsOverviewThreshold() / 100f; setIsInAllAppsRegion(mCurrentShift.value >= threshold); updateSysUiFlags(mCurrentShift.value); @@ -1000,6 +1009,8 @@ public void onRecentsAnimationStart(RecentsAnimationController controller, mStateCallback.runOnceAtState(STATE_APP_CONTROLLER_RECEIVED | STATE_GESTURE_STARTED, this::startInterceptingTouchesForGesture); mStateCallback.setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED); + + mPassedOverviewThreshold = false; } @Override @@ -1287,11 +1298,19 @@ private GestureEndTarget calculateEndTargetForFlingY(PointF velocity, float endV return willGoToNewTask || isCenteredOnNewTask ? NEW_TASK : LAST_TASK; } + if (!mDeviceState.isFullyGesturalNavMode()) { + return (!hasReachedHomeOverviewThreshold() && willGoToNewTask) ? NEW_TASK : RECENTS; + } return willGoToNewTask ? NEW_TASK : HOME; } private GestureEndTarget calculateEndTargetForNonFling(PointF velocity) { final boolean isScrollingToNewTask = isScrollingToNewTask(); + if (!mDeviceState.isFullyGesturalNavMode()) { + return hasReachedHomeOverviewThreshold() && mGestureStarted + ? RECENTS + : (isScrollingToNewTask ? NEW_TASK : LAST_TASK); + } // Fully gestural mode. final boolean isFlingX = Math.abs(velocity.x) > mContext.getResources() @@ -1335,6 +1354,16 @@ public void setCanSlowSwipeGoHome(boolean canSlowSwipeGoHome) { mCanSlowSwipeGoHome = canSlowSwipeGoHome; } + /** + * Returns true if swipe has reached the overview threshold. + */ + private boolean hasReachedHomeOverviewThreshold() { + if (mIsTransientTaskbar) { + return mCanSlowSwipeGoHome; + } + return mCurrentShift.value > MIN_PROGRESS_FOR_OVERVIEW; + } + @UiThread private void handleNormalGestureEnd( float endVelocityPxPerMs, boolean isFling, PointF velocityPxPerMs, boolean isCancel) { diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java index 7adce74f8cb..bc866662da6 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java @@ -24,6 +24,7 @@ import static com.android.launcher3.util.DisplayController.CHANGE_ROTATION; import static com.android.launcher3.util.NavigationMode.NO_BUTTON; import static com.android.launcher3.util.NavigationMode.THREE_BUTTONS; +import static com.android.launcher3.util.NavigationMode.TWO_BUTTONS; import static com.android.launcher3.util.SettingsCache.ONE_HANDED_ENABLED; import static com.android.launcher3.util.SettingsCache.ONE_HANDED_SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE; @@ -315,6 +316,13 @@ public boolean isGesturalNavMode() { return mMode.hasGestures; } + /** + * @return whether the current nav mode is 2-button-based. + */ + public boolean isTwoButtonNavMode() { + return mMode == TWO_BUTTONS; + } + /** * @return whether the current nav mode is button-based. */ diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java index 0d450c6b15e..96824e4dd61 100644 --- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java +++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java @@ -35,6 +35,8 @@ import android.content.ContextWrapper; import android.content.Intent; import android.graphics.PointF; +import android.os.Handler; +import android.os.Looper; import android.util.Log; import android.view.MotionEvent; import android.view.VelocityTracker; @@ -60,6 +62,7 @@ import com.android.quickstep.util.CachedEventDispatcher; import com.android.quickstep.util.MotionPauseDetector; import com.android.quickstep.util.NavBarPosition; +import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.InputChannelCompat.InputEventReceiver; import com.android.systemui.shared.system.InputMonitorCompat; @@ -121,6 +124,12 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC // The callback called upon finishing the recents transition if it was force-canceled private Runnable mForceFinishRecentsTransitionCallback; + private Handler mMainThreadHandler; + private Runnable mCancelRecentsAnimationRunnable = () -> { + ActivityManagerWrapper.getInstance().cancelRecentsAnimation( + true /* restoreHomeStackPosition */); + }; + public OtherActivityInputConsumer(Context base, RecentsAnimationDeviceState deviceState, TaskAnimationManager taskAnimationManager, GestureState gestureState, boolean isDeferredDownTarget, Consumer onCompleteCallback, @@ -131,6 +140,7 @@ public OtherActivityInputConsumer(Context base, RecentsAnimationDeviceState devi mNavBarPosition = mDeviceState.getNavBarPosition(); mTaskAnimationManager = taskAnimationManager; mGestureState = gestureState; + mMainThreadHandler = new Handler(Looper.getMainLooper()); mHandlerFactory = handlerFactory; mMotionPauseDetector = new MotionPauseDetector(base, false, @@ -459,6 +469,15 @@ private void finishTouchTracking(MotionEvent ev) { } onConsumerAboutToBeSwitched(); onInteractionGestureFinished(); + + // Cancel the recents animation if SysUI happens to handle UP before we have a chance + // to start the recents animation. In addition, workaround for b/126336729 by delaying + // the cancel of the animation for a period, in case SysUI is slow to handle UP and we + // handle DOWN & UP and move the home stack before SysUI can start the activity + mMainThreadHandler.removeCallbacks(mCancelRecentsAnimationRunnable); + if (!mDeviceState.isFullyGesturalNavMode()) { + mMainThreadHandler.postDelayed(mCancelRecentsAnimationRunnable, 100); + } } cleanupAfterGesture(); TraceHelper.INSTANCE.endSection(); @@ -480,6 +499,7 @@ public void notifyOrientationSetup() { @Override public void onConsumerAboutToBeSwitched() { Preconditions.assertUIThread(); + mMainThreadHandler.removeCallbacks(mCancelRecentsAnimationRunnable); if (mInteractionHandler != null) { // The consumer is being switched while we are active. Set up the shared state to be // used by the next animation From 4990890c55f7c07a8ad5ae908032847921040177 Mon Sep 17 00:00:00 2001 From: Bruno Martins Date: Thu, 12 Oct 2023 17:52:52 +0100 Subject: [PATCH 036/164] DerpLauncher: Unconditionally hide split option for Go-enabled targets Split option should be disabled for Go-enabled targets as seen in go/quickstep/res/layout/overview_actions_container.xml. Here's the snippet: