diff --git a/Omega/res/values/strings.xml b/Omega/res/values/strings.xml index 16f5855e1d..96c2527d26 100644 --- a/Omega/res/values/strings.xml +++ b/Omega/res/values/strings.xml @@ -51,6 +51,7 @@ Dock Hide Hide Labels + Colored icons Show Search Bar diff --git a/Omega/res/xml/custom_widgets.xml b/Omega/res/xml/custom_widgets.xml new file mode 100644 index 0000000000..9dc24ab74e --- /dev/null +++ b/Omega/res/xml/custom_widgets.xml @@ -0,0 +1,35 @@ + + + + + + \ No newline at end of file diff --git a/Omega/res/xml/omega_preferences_dock.xml b/Omega/res/xml/omega_preferences_dock.xml index 3c54e759be..bf87ab9f94 100644 --- a/Omega/res/xml/omega_preferences_dock.xml +++ b/Omega/res/xml/omega_preferences_dock.xml @@ -18,8 +18,8 @@ @@ -30,4 +30,18 @@ android:persistent="true" android:title="@string/title__dock_hide_labels" app:iconSpaceReserved="false" /> + \ No newline at end of file diff --git a/Omega/src/com/saggitt/omega/OmegaPreferences.kt b/Omega/src/com/saggitt/omega/OmegaPreferences.kt index a63a8f9283..e37b0462b5 100644 --- a/Omega/src/com/saggitt/omega/OmegaPreferences.kt +++ b/Omega/src/com/saggitt/omega/OmegaPreferences.kt @@ -88,12 +88,14 @@ class OmegaPreferences(val context: Context) : SharedPreferences.OnSharedPrefere val homeLabelRows get() = if (homeMultilineLabel) 2 else 1 /* --DOCK-- */ - var dockHide by BooleanPref("pref_key__hide_hotseat", false, recreate) + var dockHide by BooleanPref("pref_hideHotseat", false, recreate) val dockTextScale by FloatPref("pref_dockTextScale", -1f, restart) private val dockMultilineLabel by BooleanPref("pref_dockIconLabelsInTwoLines", false, recreate) val dockLabelRows get() = if (dockMultilineLabel) 2 else 1 val hideDockLabels by BooleanPref("pref_hideDockLabels", true, restart) var dockScale by FloatPref("pref_dockScale", -1f, recreate) + var dockSearchBarPref by BooleanPref("pref_dockSearchBar", false, recreate) + inline val dockSearchBar get() = !dockHide && dockSearchBarPref /* --THEME-- */ var launcherTheme by StringIntPref("pref_launcherTheme", 1) { ThemeManager.getInstance(context).updateTheme() } diff --git a/Omega/src/com/saggitt/omega/qsb/HotseatQsbWidget.java b/Omega/src/com/saggitt/omega/qsb/HotseatQsbWidget.java index b0067fc29a..f0c719c29e 100644 --- a/Omega/src/com/saggitt/omega/qsb/HotseatQsbWidget.java +++ b/Omega/src/com/saggitt/omega/qsb/HotseatQsbWidget.java @@ -65,7 +65,7 @@ public HotseatQsbWidget(Context context, AttributeSet attributeSet, int i) { static void a(HotseatQsbWidget hotseatQsbWidget) { if (hotseatQsbWidget.mIsGoogleColored != hotseatQsbWidget.isGoogleColored()) { hotseatQsbWidget.mIsGoogleColored = !hotseatQsbWidget.mIsGoogleColored; - hotseatQsbWidget.onChangeListener(); + hotseatQsbWidget.onChange(); } } @@ -105,6 +105,9 @@ public void setWidgetMode(boolean widgetMode) { } protected void onAttachedToWindow() { + Utilities.getOmegaPrefs(getContext()) + .addOnPreferenceChangeListener(this, KEY_DOCK_COLORED_GOOGLE, KEY_DOCK_SEARCHBAR); + dW(); super.onAttachedToWindow(); Ds.addListener(this); @@ -114,6 +117,9 @@ protected void onAttachedToWindow() { protected void onDetachedFromWindow() { super.onDetachedFromWindow(); + Utilities.getOmegaPrefs(getContext()) + .removeOnPreferenceChangeListener(this, KEY_DOCK_COLORED_GOOGLE, + KEY_DOCK_SEARCHBAR); Ds.removeListener(this); } @@ -121,10 +127,10 @@ protected void onDetachedFromWindow() { public void onValueChanged(@NotNull String key, @NotNull OmegaPreferences prefs, boolean force) { if (key.equals(KEY_DOCK_COLORED_GOOGLE)) { mIsGoogleColored = isGoogleColored(); - onChangeListener(); + onChange(); } else if (!widgetMode && (key.equals(KEY_DOCK_SEARCHBAR) || key.equals(KEY_DOCK_HIDE))) { - //boolean visible = prefs.getDockSearchBar() && !prefs.getDockHide(); - //setVisibility(visible ? View.VISIBLE : View.GONE); + boolean visible = prefs.getDockSearchBar() && !prefs.getDockHide(); + setVisibility(visible ? View.VISIBLE : View.GONE); } } @@ -138,7 +144,7 @@ protected Drawable getMicIcon() { return getMicIcon(mIsGoogleColored); } - public final void onChangeListener() { + public final void onChange() { removeAllViews(); setColors(); dW(); @@ -324,9 +330,4 @@ public void setAlpha(float alpha) { super.setAlpha(alpha); mLauncher.findViewById(R.id.scrim_view).invalidate(); } - - @Override - public void onChange() { - - } } diff --git a/Omega/src/com/saggitt/omega/qsb/QsbConfiguration.java b/Omega/src/com/saggitt/omega/qsb/QsbConfiguration.java index 044f77d15f..3e45c6902e 100644 --- a/Omega/src/com/saggitt/omega/qsb/QsbConfiguration.java +++ b/Omega/src/com/saggitt/omega/qsb/QsbConfiguration.java @@ -32,6 +32,12 @@ private QsbConfiguration(Context context) { } + private void notifyListeners() { + for (QsbChangeListener listener : mListeners) { + listener.onChange(); + } + } + public static QsbConfiguration getInstance(Context context) { if (INSTANCE == null) { INSTANCE = new QsbConfiguration(context.getApplicationContext()); diff --git a/Omega/src/com/saggitt/omega/widget/CustomWidgetParser.java b/Omega/src/com/saggitt/omega/widget/CustomWidgetParser.java new file mode 100644 index 0000000000..9018677f8b --- /dev/null +++ b/Omega/src/com/saggitt/omega/widget/CustomWidgetParser.java @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2020 Omega Launcher + * + * 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.saggitt.omega.widget; + +import android.appwidget.AppWidgetManager; +import android.appwidget.AppWidgetProviderInfo; +import android.content.ComponentName; +import android.content.Context; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.os.Parcel; +import android.os.Process; +import android.util.SparseArray; +import android.util.Xml; + +import com.android.launcher3.LauncherAppWidgetInfo; +import com.android.launcher3.LauncherAppWidgetProviderInfo; +import com.android.launcher3.R; +import com.android.launcher3.widget.custom.CustomAppWidgetProviderInfo; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import static com.android.launcher3.LauncherAppWidgetProviderInfo.CLS_CUSTOM_WIDGET_PREFIX; + +/** + * Utility class to parse {@ink CustomAppWidgetProviderInfo} definitions from xml + */ +public class CustomWidgetParser { + + private static List sCustomWidgets; + private static SparseArray sWidgetsIdMap; + + public static List getCustomWidgets(Context context) { + if (sCustomWidgets == null) { + // Synchronization not needed as it it safe to load multiple times + parseCustomWidgets(context); + } + + return sCustomWidgets; + } + + public static int getWidgetIdForCustomProvider(Context context, ComponentName provider) { + if (sWidgetsIdMap == null) { + parseCustomWidgets(context); + } + int index = sWidgetsIdMap.indexOfValue(provider); + if (index >= 0) { + return LauncherAppWidgetInfo.CUSTOM_WIDGET_ID - sWidgetsIdMap.keyAt(index); + } else { + return AppWidgetManager.INVALID_APPWIDGET_ID; + } + } + + public static LauncherAppWidgetProviderInfo getWidgetProvider(Context context, int widgetId) { + if (sWidgetsIdMap == null || sCustomWidgets == null) { + parseCustomWidgets(context); + } + ComponentName cn = sWidgetsIdMap.get(LauncherAppWidgetInfo.CUSTOM_WIDGET_ID - widgetId); + for (LauncherAppWidgetProviderInfo info : sCustomWidgets) { + if (info.provider.equals(cn)) { + return info; + } + } + return null; + } + + private static void parseCustomWidgets(Context context) { + ArrayList widgets = new ArrayList<>(); + SparseArray idMap = new SparseArray<>(); + + List providers = AppWidgetManager.getInstance(context) + .getInstalledProvidersForProfile(Process.myUserHandle()); + if (providers.isEmpty()) { + sCustomWidgets = widgets; + sWidgetsIdMap = idMap; + return; + } + + Parcel parcel = Parcel.obtain(); + providers.get(0).writeToParcel(parcel, 0); + + try (XmlResourceParser parser = context.getResources().getXml(R.xml.custom_widgets)) { + final int depth = parser.getDepth(); + int type; + + while (((type = parser.next()) != XmlPullParser.END_TAG || + parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) { + if ((type == XmlPullParser.START_TAG) && "widget".equals(parser.getName())) { + TypedArray a = context.obtainStyledAttributes( + Xml.asAttributeSet(parser), R.styleable.CustomAppWidgetProviderInfo); + + parcel.setDataPosition(0); + CustomAppWidgetProviderInfo info = newInfo(a, parcel, context); + widgets.add(info); + a.recycle(); + + idMap.put(info.providerId, info.provider); + } + } + } catch (IOException | XmlPullParserException e) { + throw new RuntimeException(e); + } + parcel.recycle(); + sCustomWidgets = widgets; + sWidgetsIdMap = idMap; + } + + private static CustomAppWidgetProviderInfo newInfo(TypedArray a, Parcel parcel, Context context) { + int providerId = a.getInt(R.styleable.CustomAppWidgetProviderInfo_providerId, 0); + boolean noPadding = a.getBoolean(R.styleable.CustomAppWidgetProviderInfo_noPadding, false); + CustomAppWidgetProviderInfo info = new CustomAppWidgetProviderInfo(parcel, false, providerId, noPadding); + info.provider = new ComponentName(context.getPackageName(), CLS_CUSTOM_WIDGET_PREFIX + providerId); + info.customizeTitle = a.getResourceId(R.styleable.CustomAppWidgetProviderInfo_customizeTitle, 0); + info.customizeScreen = a.getResourceId(R.styleable.CustomAppWidgetProviderInfo_customizeScreen, 0); + info.customizeHasPreview = a.getBoolean(R.styleable.CustomAppWidgetProviderInfo_customizeHasPreview, false); + + info.label = a.getString(R.styleable.CustomAppWidgetProviderInfo_android_label); + info.initialLayout = a.getResourceId(R.styleable.CustomAppWidgetProviderInfo_android_initialLayout, 0); + info.icon = a.getResourceId(R.styleable.CustomAppWidgetProviderInfo_android_icon, 0); + info.previewImage = a.getResourceId(R.styleable.CustomAppWidgetProviderInfo_android_previewImage, 0); + info.resizeMode = a.getInt(R.styleable.CustomAppWidgetProviderInfo_android_resizeMode, 0); + + info.spanX = a.getInt(R.styleable.CustomAppWidgetProviderInfo_numColumns, 1); + info.spanY = a.getInt(R.styleable.CustomAppWidgetProviderInfo_numRows, 1); + info.minSpanX = a.getInt(R.styleable.CustomAppWidgetProviderInfo_numMinColumns, 1); + info.minSpanY = a.getInt(R.styleable.CustomAppWidgetProviderInfo_numMinRows, 1); + return info; + } +} diff --git a/res/values/dimens.xml b/res/values/dimens.xml index a00ec0113f..4e9ea56f53 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -29,8 +29,8 @@ 8dp - 4dp - 2dp + 8dp + 62dp 0dp 34dp @@ -41,7 +41,7 @@ 24dp 0dp - + 48dp 20dp diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java index ac4396778a..85b68c8672 100644 --- a/src/com/android/launcher3/AutoInstallsLayout.java +++ b/src/com/android/launcher3/AutoInstallsLayout.java @@ -48,6 +48,8 @@ import com.android.launcher3.util.IntArray; import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.Thunk; +import com.android.launcher3.widget.custom.CustomAppWidgetProviderInfo; +import com.saggitt.omega.widget.CustomWidgetParser; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -131,6 +133,7 @@ static AutoInstallsLayout get(Context context, AppWidgetHost appWidgetHost, private static final String ATTR_CLASS_NAME = "className"; private static final String ATTR_TITLE = "title"; private static final String ATTR_SCREEN = "screen"; + private static final String ATTR_PROVIDER_ID = "providerId"; // x and y can be specified as negative integers, in which case -1 represents the // last row / column, -2 represents the second last, and so on. @@ -564,6 +567,76 @@ protected int verifyAndInsert(ComponentName cn, Bundle extras) { } } + protected class CustomAppWidgetParser implements TagParser { + + @Override + public int parseAndAdd(XmlPullParser parser) + throws XmlPullParserException, IOException { + final int providerId = Integer.parseInt(getAttributeValue(parser, ATTR_PROVIDER_ID)); + LauncherAppWidgetProviderInfo provider = null; + + for (LauncherAppWidgetProviderInfo each : CustomWidgetParser.getCustomWidgets(mContext)) { + if (each instanceof CustomAppWidgetProviderInfo) { + if (((CustomAppWidgetProviderInfo) each).providerId == providerId) { + provider = each; + break; + } + } + } + + if (provider == null) { + if (LOGD) Log.d(TAG, "Skipping invalid with no provider"); + return -1; + } + + mValues.put(Favorites.SPANX, getAttributeValue(parser, ATTR_SPAN_X)); + mValues.put(Favorites.SPANY, getAttributeValue(parser, ATTR_SPAN_Y)); + mValues.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_CUSTOM_APPWIDGET); + mValues.put(Favorites.APPWIDGET_ID, CustomWidgetParser + .getWidgetIdForCustomProvider(mContext, provider.provider)); + + // Read the extras + Bundle extras = new Bundle(); + int widgetDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_TAG || + parser.getDepth() > widgetDepth) { + if (type != XmlPullParser.START_TAG) { + continue; + } + + if (TAG_EXTRA.equals(parser.getName())) { + String key = getAttributeValue(parser, ATTR_KEY); + String value = getAttributeValue(parser, ATTR_VALUE); + if (key != null && value != null) { + extras.putString(key, value); + } else { + throw new RuntimeException("Widget extras must have a key and value"); + } + } else { + throw new RuntimeException("Widgets can contain only extras"); + } + } + + return verifyAndInsert(provider.provider, extras); + } + + protected int verifyAndInsert(ComponentName cn, Bundle extras) { + mValues.put(Favorites.APPWIDGET_PROVIDER, cn.flattenToString()); + mValues.put(Favorites._ID, mCallback.generateNewItemId()); + if (!extras.isEmpty()) { + mValues.put(Favorites.INTENT, new Intent().putExtras(extras).toUri(0)); + } + + int insertedId = mCallback.insertAndCheck(mDb, mValues); + if (insertedId < 0) { + return -1; + } else { + return insertedId; + } + } + } + protected class FolderParser implements TagParser { private final ArrayMap mFolderElements; diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index 328332e6b2..8dc01ad7de 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -288,7 +288,7 @@ public DeviceProfile(Context context, InvariantDeviceProfile inv, topWorkspacePadding = res.getDimensionPixelSize(R.dimen.dynamic_grid_workspace_top_padding); - prefs.addOnPreferenceChangeListener(this, "pref_fullWidthWidgets"); + prefs.addOnPreferenceChangeListener(this, "pref_fullWidthWidgets", "pref_dockSearchBar"); } @Override @@ -301,6 +301,7 @@ public void updateDimensions() { DisplayMetrics dm = res.getDisplayMetrics(); boolean fullWidthWidgets = Utilities.getOmegaPrefs(mContext).getAllowFullWidthWidgets(); + boolean dockSearchBar = prefs.getDockSearchBar(); boolean dockHidden = prefs.getDockHide(); float dockScale = prefs.getDockScale(); @@ -308,8 +309,16 @@ public void updateDimensions() { : res.getDimensionPixelSize(R.dimen.dynamic_grid_cell_layout_padding); hotseatBarTopPaddingPx = - res.getDimensionPixelSize(R.dimen.v1_dynamic_grid_hotseat_top_padding); - int extraHotseatBottomPadding = res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_bottom_non_tall_padding); + res.getDimensionPixelSize(dockSearchBar ? + R.dimen.dynamic_grid_hotseat_top_padding : + R.dimen.v1_dynamic_grid_hotseat_top_padding); + + int extraHotseatBottomPadding = 0; //!prefs.getDockGradientStyle() ? 0 + // : res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_bottom_non_tall_padding); + hotseatBarBottomPaddingPx = extraHotseatBottomPadding + + res.getDimensionPixelSize(dockSearchBar ? + R.dimen.dynamic_grid_hotseat_bottom_padding : + R.dimen.v1_dynamic_grid_hotseat_bottom_padding); hotseatBarBottomPaddingPx = extraHotseatBottomPadding + res.getDimensionPixelSize( R.dimen.v1_dynamic_grid_hotseat_bottom_padding); @@ -320,8 +329,9 @@ public void updateDimensions() { hotseatBarSizePx = isVerticalBarLayout() ? hotseatIconSizePx + hotseatBarSidePaddingStartPx + hotseatBarSidePaddingEndPx - : res.getDimensionPixelSize( - R.dimen.dynamic_grid_hotseat_size) + : res.getDimensionPixelSize(dockSearchBar ? + R.dimen.dynamic_grid_hotseat_size : + R.dimen.v1_dynamic_grid_hotseat_size) + hotseatBarTopPaddingPx + hotseatBarBottomPaddingPx; verticalDragHandleSizePx = res.getDimensionPixelSize( R.dimen.vertical_drag_handle_size); @@ -374,7 +384,8 @@ public void updateDimensions() { } else if (!isVerticalBarLayout()) { float adjustedDockScale = (float) extraSpaceFromScale / hotseatBarSizePx + 1; verticalDragHandleSizePx *= adjustedDockScale; - int bottomPaddingNew = Math.max((int) (hotseatBarBottomPaddingPx * adjustedDockScale), 0); + int qsbHeight = res.getDimensionPixelSize(R.dimen.qsb_widget_height); + int bottomPaddingNew = Math.max((int) (hotseatBarBottomPaddingPx * adjustedDockScale), dockSearchBar ? qsbHeight : 0); int difference = hotseatBarBottomPaddingPx - bottomPaddingNew; hotseatBarTopPaddingPx -= difference; diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java index 6785397481..8453b1fd0e 100644 --- a/src/com/android/launcher3/Hotseat.java +++ b/src/com/android/launcher3/Hotseat.java @@ -31,6 +31,7 @@ import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.userevent.nano.LauncherLogProto.Target; import com.android.launcher3.views.Transposable; +import com.saggitt.omega.OmegaPreferences; public class Hotseat extends CellLayout implements LogContainerProvider, Insettable, Transposable { @@ -58,6 +59,23 @@ int getCellYFromOrder(int rank) { return mHasVerticalHotseat ? (getCountY() - (rank + 1)) : 0; } + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + + OmegaPreferences prefs = Utilities.getOmegaPrefs(getContext()); + if (prefs.getDockHide()) { + setVisibility(GONE); + } else if (prefs.getDockSearchBar()) { + inflate(getContext(), R.layout.search_container_hotseat, this); + } else { + View v = this.findViewById(R.id.search_container_hotseat); + if (v != null) { + removeView(v); + } + } + } + public void resetLayout(boolean hasVerticalHotseat) { removeAllViewsInLayout(); mHasVerticalHotseat = hasVerticalHotseat; diff --git a/src/com/android/launcher3/widget/custom/CustomAppWidgetProviderInfo.java b/src/com/android/launcher3/widget/custom/CustomAppWidgetProviderInfo.java index d7bff8c06f..fbf37d094e 100644 --- a/src/com/android/launcher3/widget/custom/CustomAppWidgetProviderInfo.java +++ b/src/com/android/launcher3/widget/custom/CustomAppWidgetProviderInfo.java @@ -73,8 +73,8 @@ public String toString() { return "WidgetProviderInfo(" + provider + ")"; } - protected CustomAppWidgetProviderInfo(Parcel parcel, boolean readSelf, - int providerId, boolean noPadding) { + public CustomAppWidgetProviderInfo(Parcel parcel, boolean readSelf, + int providerId, boolean noPadding) { super(parcel); if (readSelf) { this.providerId = parcel.readInt();