summaryrefslogtreecommitdiffstats
path: root/src/com
diff options
context:
space:
mode:
Diffstat (limited to 'src/com')
-rw-r--r--src/com/android/launcher3/AppWidgetResizeFrame.java24
-rw-r--r--src/com/android/launcher3/BubbleTextView.java17
-rw-r--r--src/com/android/launcher3/DeviceProfile.java17
-rw-r--r--src/com/android/launcher3/InvariantDeviceProfile.java33
-rw-r--r--src/com/android/launcher3/Launcher.java8
-rw-r--r--src/com/android/launcher3/PagedView.java6
-rw-r--r--src/com/android/launcher3/Utilities.java22
-rw-r--r--src/com/android/launcher3/Workspace.java3
-rw-r--r--src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java28
-rw-r--r--src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java3
-rw-r--r--src/com/android/launcher3/config/BaseFlags.java7
-rw-r--r--src/com/android/launcher3/dragndrop/DragController.java6
-rw-r--r--src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java2
-rw-r--r--src/com/android/launcher3/lineage/LineageLauncher.java32
-rw-r--r--src/com/android/launcher3/lineage/LineageLauncherCallbacks.java204
-rw-r--r--src/com/android/launcher3/lineage/LineageUtils.java78
-rw-r--r--src/com/android/launcher3/lineage/OverlayCallbackImpl.java80
-rw-r--r--src/com/android/launcher3/lineage/trust/HiddenAppsFilter.java40
-rw-r--r--src/com/android/launcher3/lineage/trust/LoadTrustComponentsTask.java104
-rw-r--r--src/com/android/launcher3/lineage/trust/TrustAppsActivity.java157
-rw-r--r--src/com/android/launcher3/lineage/trust/TrustAppsAdapter.java197
-rw-r--r--src/com/android/launcher3/lineage/trust/UpdateItemTask.java76
-rw-r--r--src/com/android/launcher3/lineage/trust/db/TrustComponent.java92
-rw-r--r--src/com/android/launcher3/lineage/trust/db/TrustDatabaseHelper.java198
-rw-r--r--src/com/android/launcher3/popup/PopupContainerWithArrow.java3
-rw-r--r--src/com/android/launcher3/popup/SystemShortcut.java2
-rw-r--r--src/com/android/launcher3/provider/ImportDataTask.java2
-rw-r--r--src/com/android/launcher3/qsb/QsbContainerView.java29
-rw-r--r--src/com/android/launcher3/qsb/QsbWidgetHostView.java6
-rw-r--r--src/com/android/launcher3/settings/SettingsActivity.java57
-rw-r--r--src/com/android/launcher3/touch/ItemClickHandler.java13
-rw-r--r--src/com/android/launcher3/util/PackageManagerHelper.java5
-rw-r--r--src/com/android/launcher3/views/OptionsPopupView.java21
33 files changed, 1466 insertions, 106 deletions
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index f9a8d1bbe..b377c0ce6 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -9,7 +9,6 @@ import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.appwidget.AppWidgetHostView;
-import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
@@ -76,8 +75,6 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
private boolean mTopBorderActive;
private boolean mBottomBorderActive;
- private int mResizeMode;
-
private int mRunningHInc;
private int mRunningVInc;
private int mMinHSpan;
@@ -160,7 +157,6 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
mWidgetView = widgetView;
LauncherAppWidgetProviderInfo info = (LauncherAppWidgetProviderInfo)
widgetView.getAppWidgetInfo();
- mResizeMode = info.resizeMode;
mDragLayer = dragLayer;
mMinHSpan = info.minSpanX;
@@ -169,14 +165,6 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
mWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(getContext(),
widgetView.getAppWidgetInfo().provider, null);
- if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) {
- mDragHandles[INDEX_TOP].setVisibility(GONE);
- mDragHandles[INDEX_BOTTOM].setVisibility(GONE);
- } else if (mResizeMode == AppWidgetProviderInfo.RESIZE_VERTICAL) {
- mDragHandles[INDEX_LEFT].setVisibility(GONE);
- mDragHandles[INDEX_RIGHT].setVisibility(GONE);
- }
-
// When we create the resize frame, we first mark all cells as unoccupied. The appropriate
// cells (same if not resized, or different) will be marked as occupied when the resize
// frame is dismissed.
@@ -186,14 +174,10 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
}
public boolean beginResizeIfPointInRegion(int x, int y) {
- boolean horizontalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0;
- boolean verticalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0;
-
- mLeftBorderActive = (x < mTouchTargetWidth) && horizontalActive;
- mRightBorderActive = (x > getWidth() - mTouchTargetWidth) && horizontalActive;
- mTopBorderActive = (y < mTouchTargetWidth + mTopTouchRegionAdjustment) && verticalActive;
- mBottomBorderActive = (y > getHeight() - mTouchTargetWidth + mBottomTouchRegionAdjustment)
- && verticalActive;
+ 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/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 7adb6a442..5e73880a8 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -16,12 +16,15 @@
package com.android.launcher3;
+import static com.android.launcher3.InvariantDeviceProfile.KEY_SHOW_DESKTOP_LABELS;
+import static com.android.launcher3.InvariantDeviceProfile.KEY_SHOW_DRAWER_LABELS;
import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
+import android.content.SharedPreferences;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Canvas;
@@ -72,7 +75,6 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
private static final int[] STATE_PRESSED = new int[] {android.R.attr.state_pressed};
-
private static final Property<BubbleTextView, Float> DOT_SCALE_PROPERTY
= new Property<BubbleTextView, Float>(Float.TYPE, "dotScale") {
@Override
@@ -134,10 +136,11 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
private boolean mIgnorePressedStateChange;
@ViewDebug.ExportedProperty(category = "launcher")
private boolean mDisableRelayout = false;
-
@ViewDebug.ExportedProperty(category = "launcher")
private final boolean mIgnorePaddingTouch;
+ private boolean mShouldShowLabel;
+
private IconLoadRequest mIconLoadRequest;
public BubbleTextView(Context context) {
@@ -157,6 +160,8 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
R.styleable.BubbleTextView, defStyle, 0);
mLayoutHorizontal = a.getBoolean(R.styleable.BubbleTextView_layoutHorizontal, false);
+ SharedPreferences prefs = Utilities.getPrefs(context.getApplicationContext());
+
mDisplay = a.getInteger(R.styleable.BubbleTextView_iconDisplay, DISPLAY_WORKSPACE);
final int defaultIconSize;
if (mDisplay == DISPLAY_WORKSPACE) {
@@ -164,12 +169,14 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx);
setCompoundDrawablePadding(grid.iconDrawablePaddingPx);
defaultIconSize = grid.iconSizePx;
+ mShouldShowLabel = prefs.getBoolean(KEY_SHOW_DESKTOP_LABELS, true);
mIgnorePaddingTouch = true;
} else if (mDisplay == DISPLAY_ALL_APPS) {
DeviceProfile grid = mActivity.getDeviceProfile();
setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.allAppsIconTextSizePx);
setCompoundDrawablePadding(grid.allAppsIconDrawablePaddingPx);
defaultIconSize = grid.allAppsIconSizePx;
+ mShouldShowLabel = prefs.getBoolean(KEY_SHOW_DRAWER_LABELS, true);
mIgnorePaddingTouch = true;
} else if (mDisplay == DISPLAY_FOLDER) {
DeviceProfile grid = mActivity.getDeviceProfile();
@@ -177,10 +184,12 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
setCompoundDrawablePadding(grid.folderChildDrawablePaddingPx);
defaultIconSize = grid.folderChildIconSizePx;
mIgnorePaddingTouch = true;
+ mShouldShowLabel = prefs.getBoolean(KEY_SHOW_DESKTOP_LABELS, true);
} else {
// widget_selection or shortcut_popup
defaultIconSize = mActivity.getDeviceProfile().iconSizePx;
mIgnorePaddingTouch = false;
+ mShouldShowLabel = prefs.getBoolean(KEY_SHOW_DESKTOP_LABELS, true);
}
mCenterVertically = a.getBoolean(R.styleable.BubbleTextView_centerVertically, false);
@@ -292,7 +301,9 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
mDotParams.color = IconPalette.getMutedColor(info.iconColor, 0.54f);
setIcon(iconDrawable);
- setText(info.title);
+ if (mShouldShowLabel) {
+ setText(info.title);
+ }
if (info.contentDescription != null) {
setContentDescription(info.isDisabled()
? getContext().getString(R.string.disabled_app_label, info.contentDescription)
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index bc6fa6e90..0ffe2d77c 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -16,7 +16,10 @@
package com.android.launcher3;
+import static com.android.launcher3.InvariantDeviceProfile.KEY_SHOW_LABELS_LANDSCAPE;
+
import android.content.Context;
+import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Point;
@@ -137,6 +140,8 @@ public class DeviceProfile {
public DotRenderer mDotRendererWorkSpace;
public DotRenderer mDotRendererAllApps;
+ private SharedPreferences mPrefs;
+
public DeviceProfile(Context context, InvariantDeviceProfile inv,
InvariantDeviceProfile originalIDP, Point minSize, Point maxSize,
int width, int height, boolean isLandscape, boolean isMultiWindowMode) {
@@ -171,6 +176,8 @@ public class DeviceProfile {
transposeLayoutWithOrientation =
res.getBoolean(R.bool.hotseat_transpose_layout_with_orientation);
+ mPrefs = Utilities.getPrefs(context.getApplicationContext());
+
context = getContext(context, isVerticalBarLayout()
? Configuration.ORIENTATION_LANDSCAPE
: Configuration.ORIENTATION_PORTRAIT);
@@ -362,8 +369,8 @@ public class DeviceProfile {
allAppsCellHeightPx = getCellSize().y;
allAppsCellWidthPx = allAppsIconSizePx + allAppsIconDrawablePaddingPx;
- if (isVerticalBarLayout()) {
- // Always hide the Workspace text with vertical bar layout.
+ if (isVerticalBarLayout() && !mPrefs.getBoolean(KEY_SHOW_LABELS_LANDSCAPE, false)) {
+ // Hide Workspace text with vertical bar layout if needed.
adjustToHideWorkspaceLabels();
}
@@ -559,9 +566,15 @@ public class DeviceProfile {
}
public static int calculateCellWidth(int width, int countX) {
+ if (countX == 0) {
+ countX = 4;
+ }
return width / countX;
}
public static int calculateCellHeight(int height, int countY) {
+ if (countY == 0) {
+ countY = 5;
+ }
return height / countY;
}
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index d66ba7317..b80cff810 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -19,7 +19,6 @@ package com.android.launcher3;
import static com.android.launcher3.Utilities.getDevicePrefs;
import static com.android.launcher3.config.FeatureFlags.APPLY_CONFIG_AT_RUNTIME;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-import static com.android.launcher3.settings.SettingsActivity.GRID_OPTIONS_PREFERENCE_KEY;
import static com.android.launcher3.util.PackageManagerHelper.getPackageFilter;
import android.annotation.TargetApi;
@@ -28,6 +27,8 @@ import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -60,7 +61,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
-public class InvariantDeviceProfile {
+public class InvariantDeviceProfile implements OnSharedPreferenceChangeListener {
public static final String TAG = "IDP";
// We do not need any synchronization for this variable as its only written on UI thread.
@@ -74,7 +75,11 @@ public class InvariantDeviceProfile {
public static final int CHANGE_FLAG_GRID = 1 << 0;
public static final int CHANGE_FLAG_ICON_PARAMS = 1 << 1;
+ public static final String KEY_SHOW_DESKTOP_LABELS = "pref_desktop_show_labels";
+ public static final String KEY_SHOW_DRAWER_LABELS = "pref_drawer_show_labels";
+ public static final String KEY_SHOW_LABELS_LANDSCAPE = "pref_show_labels_landscape";
public static final String KEY_ICON_PATH_REF = "pref_icon_shape_path";
+ public static final String KEY_WORKSPACE_EDIT = "pref_workspace_edit";
// Constants that affects the interpolation curve between statically defined device profile
// buckets.
@@ -132,6 +137,8 @@ public class InvariantDeviceProfile {
private ConfigMonitor mConfigMonitor;
private OverlayMonitor mOverlayMonitor;
+ private Context mContext;
+
@VisibleForTesting
public InvariantDeviceProfile() {}
@@ -156,9 +163,12 @@ public class InvariantDeviceProfile {
@TargetApi(23)
private InvariantDeviceProfile(Context context) {
- String gridName = Utilities.getPrefs(context).getBoolean(GRID_OPTIONS_PREFERENCE_KEY, false)
- ? Utilities.getPrefs(context).getString(KEY_IDP_GRID_NAME, null)
- : null;
+ mContext = context;
+
+ SharedPreferences prefs = Utilities.getPrefs(context);
+ prefs.registerOnSharedPreferenceChangeListener(this);
+
+ String gridName = prefs.getString(KEY_IDP_GRID_NAME, null);
initGrid(context, gridName);
mConfigMonitor = new ConfigMonitor(context,
APPLY_CONFIG_AT_RUNTIME.get() ? this::onConfigChanged : this::killProcess);
@@ -175,6 +185,15 @@ public class InvariantDeviceProfile {
}
}
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
+ if (KEY_SHOW_DESKTOP_LABELS.equals(key) || KEY_SHOW_DRAWER_LABELS.equals(key)) {
+ apply(mContext, CHANGE_FLAG_ICON_PARAMS);
+ } else if (KEY_SHOW_LABELS_LANDSCAPE.equals(key)) {
+ onConfigChanged(mContext);
+ }
+ }
+
/**
* Retrieve system defined or RRO overriden icon shape.
*/
@@ -348,9 +367,7 @@ public class InvariantDeviceProfile {
InvariantDeviceProfile oldProfile = new InvariantDeviceProfile(this);
// Re-init grid
- String gridName = Utilities.getPrefs(context).getBoolean(GRID_OPTIONS_PREFERENCE_KEY, false)
- ? Utilities.getPrefs(context).getString(KEY_IDP_GRID_NAME, null)
- : null;
+ String gridName = Utilities.getPrefs(context).getString(KEY_IDP_GRID_NAME, null);
initGrid(context, gridName);
int changeFlags = 0;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 1338b3062..68c8f1e25 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -102,6 +102,7 @@ import com.android.launcher3.graphics.RotationMode;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.keyboard.CustomActionsPopup;
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
+import com.android.launcher3.lineage.LineageUtils;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.logging.StatsLogUtils;
import com.android.launcher3.logging.UserEventDispatcher;
@@ -1022,6 +1023,13 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
mStateManager.onWindowFocusChanged();
}
+ public void startActivitySafelyAuth(View v, Intent intent, ItemInfo item,
+ String sourceContainer) {
+ LineageUtils.showLockScreen(this, getString(R.string.trust_apps_manager_name), () -> {
+ startActivitySafely(v, intent, item, sourceContainer);
+ });
+ }
+
public interface LauncherOverlay {
/**
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index ff2b40038..1fccd4f7b 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -1163,6 +1163,12 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
if (mIsBeingDragged) {
final int activePointerId = mActivePointerId;
final int pointerIndex = ev.findPointerIndex(activePointerId);
+
+ if (pointerIndex == -1) {
+ onScrollInteractionEnd();
+ return true;
+ }
+
final float x = ev.getX(pointerIndex);
final VelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 5d0effa5f..108898e99 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -46,7 +46,6 @@ import android.os.Handler;
import android.os.Message;
import android.os.PowerManager;
import android.os.TransactionTooLargeException;
-import android.provider.Settings;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
@@ -68,7 +67,6 @@ import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.IntArray;
-import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.views.Transposable;
import com.android.launcher3.widget.PendingAddShortcutInfo;
@@ -117,14 +115,7 @@ public final class Utilities {
* Indicates if the device has a debug build. Should only be used to store additional info or
* add extra logging and not for changing the app behavior.
*/
- public static final boolean IS_DEBUG_DEVICE =
- Build.TYPE.toLowerCase(Locale.ROOT).contains("debug") ||
- Build.TYPE.toLowerCase(Locale.ROOT).equals("eng");
-
- public static boolean isDevelopersOptionsEnabled(Context context) {
- return Settings.Global.getInt(context.getApplicationContext().getContentResolver(),
- Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0;
- }
+ public static final boolean IS_DEBUG_DEVICE = false;
// An intent extra to indicate the horizontal scroll of the wallpaper.
public static final String EXTRA_WALLPAPER_OFFSET = "com.android.launcher3.WALLPAPER_OFFSET";
@@ -141,12 +132,6 @@ public final class Utilities {
return Log.isLoggable(propertyName, Log.VERBOSE);
}
- public static boolean existsStyleWallpapers(Context context) {
- ResolveInfo ri = context.getPackageManager().resolveActivity(
- PackageManagerHelper.getStyleWallpapersIntent(context), 0);
- return ri != null;
- }
-
/**
* Given a coordinate relative to the descendant, find the coordinate in a parent view's
* coordinates.
@@ -624,4 +609,9 @@ public final class Utilities {
return mSize;
}
}
+
+ public static boolean isWorkspaceEditAllowed(Context context) {
+ SharedPreferences prefs = getPrefs(context.getApplicationContext());
+ return prefs.getBoolean(InvariantDeviceProfile.KEY_WORKSPACE_EDIT, true);
+ }
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 9eeb2866b..fcb4db78c 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -1887,8 +1887,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
final LauncherAppWidgetHostView hostView = (LauncherAppWidgetHostView) cell;
AppWidgetProviderInfo pInfo = hostView.getAppWidgetInfo();
- if (pInfo != null && pInfo.resizeMode != AppWidgetProviderInfo.RESIZE_NONE
- && !d.accessibleDrag) {
+ if (pInfo != null && !d.accessibleDrag) {
onCompleteRunnable = new Runnable() {
public void run() {
if (!isPageInTransition()) {
diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
index 31fcc8c64..bcfdf916b 100644
--- a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
+++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
@@ -49,6 +49,7 @@ import com.android.launcher3.allapps.SearchUiManager;
import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.graphics.TintedDrawableSpan;
import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.views.ActivityContext;
import java.util.ArrayList;
@@ -61,6 +62,7 @@ public class AppsSearchContainerLayout extends ExtendedEditText
private final Launcher mLauncher;
+ private final ActivityContext mActivity;
private final AllAppsSearchBarController mSearchBarController;
private final SpannableStringBuilder mSearchQueryBuilder;
@@ -82,16 +84,27 @@ public class AppsSearchContainerLayout extends ExtendedEditText
public AppsSearchContainerLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- mLauncher = Launcher.getLauncher(context);
+ mActivity = ActivityContext.lookupContext(context);
+ mLauncher = tryGetLauncher(context);
mSearchBarController = new AllAppsSearchBarController();
mSearchQueryBuilder = new SpannableStringBuilder();
Selection.setSelection(mSearchQueryBuilder, 0);
- mFixedTranslationY = getTranslationY();
+ mFixedTranslationY = Math.round(getTranslationY());
mMarginTopAdjusting = mFixedTranslationY - getPaddingTop();
setHint(prefixTextWithIcon(getContext(), R.drawable.ic_allapps_search, getHint()));
+
+ setTranslationY(0);
+ }
+
+ private Launcher tryGetLauncher(Context context) {
+ try {
+ return Launcher.getLauncher(context);
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
}
@Override
@@ -109,11 +122,11 @@ public class AppsSearchContainerLayout extends ExtendedEditText
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Update the width to match the grid padding
- DeviceProfile dp = mLauncher.getDeviceProfile();
+ DeviceProfile dp = mActivity.getDeviceProfile();
int myRequestedWidth = getSize(widthMeasureSpec);
- int rowWidth = myRequestedWidth - mAppsView.getActiveRecyclerView().getPaddingLeft()
- - mAppsView.getActiveRecyclerView().getPaddingRight();
-
+ int leftRightPadding = dp.desiredWorkspaceLeftRightMarginPx
+ + dp.cellLayoutPaddingLeftRightPx;
+ int rowWidth = myRequestedWidth - leftRightPadding * 2;
int cellWidth = DeviceProfile.calculateCellWidth(rowWidth, dp.inv.numHotseatIcons);
int iconVisibleSize = Math.round(ICON_VISIBLE_AREA_FACTOR * dp.iconSizePx);
int iconPadding = cellWidth - iconVisibleSize;
@@ -133,6 +146,7 @@ public class AppsSearchContainerLayout extends ExtendedEditText
int expectedLeft = parent.getPaddingLeft() + (availableWidth - myWidth) / 2;
int shift = expectedLeft - left;
setTranslationX(shift);
+ offsetTopAndBottom((int) mFixedTranslationY);
}
@Override
@@ -207,7 +221,7 @@ public class AppsSearchContainerLayout extends ExtendedEditText
@Override
public float getScrollRangeDelta(Rect insets) {
- if (mLauncher.getDeviceProfile().isVerticalBarLayout()) {
+ if (mActivity.getDeviceProfile().isVerticalBarLayout()) {
return 0;
} else {
int topMargin = Math.round(Math.max(
diff --git a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
index 26f6ec357..604ac8374 100644
--- a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
+++ b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
@@ -141,7 +141,8 @@ public class DefaultAppSearchAlgorithm implements SearchAlgorithm {
// Always a break point for a symbol
return true;
default:
- return false;
+ // Always a break point at first character
+ return prevType == Character.UNASSIGNED;
}
}
diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java
index 4b90e421f..65cf1216d 100644
--- a/src/com/android/launcher3/config/BaseFlags.java
+++ b/src/com/android/launcher3/config/BaseFlags.java
@@ -20,6 +20,7 @@ import static androidx.core.util.Preconditions.checkNotNull;
import android.content.Context;
import android.content.SharedPreferences;
+import android.provider.Settings;
import androidx.annotation.GuardedBy;
import androidx.annotation.Keep;
@@ -52,7 +53,9 @@ public abstract class BaseFlags {
}
public static boolean showFlagTogglerUi(Context context) {
- return Utilities.IS_DEBUG_DEVICE && Utilities.isDevelopersOptionsEnabled(context);
+ return Utilities.IS_DEBUG_DEVICE &&
+ Settings.Global.getInt(context.getApplicationContext().getContentResolver(),
+ Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0;
}
public static final boolean IS_DOGFOOD_BUILD = false;
@@ -66,7 +69,7 @@ public abstract class BaseFlags {
"Adds a promise icon to the home screen for new install sessions.");
// Enable moving the QSB on the 0th screen of the workspace
- public static final boolean QSB_ON_FIRST_SCREEN = true;
+ public static final boolean QSB_ON_FIRST_SCREEN = false;
public static final TogglableFlag EXAMPLE_FLAG = new TogglableFlag("EXAMPLE_FLAG", true,
"An example flag that doesn't do anything. Useful for testing");
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index dcdf5d616..d845ad20c 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -41,6 +41,7 @@ import com.android.launcher3.DropTarget;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.accessibility.DragViewStateAnnouncer;
import com.android.launcher3.testing.TestProtocol;
@@ -429,6 +430,11 @@ public class DragController implements DragDriver.EventListener, TouchController
return false;
}
+ if (!Utilities.isWorkspaceEditAllowed(mLauncher.getApplicationContext())) {
+ cancelDrag();
+ return false;
+ }
+
// Update the velocity tracker
mFlingToDeleteHelper.recordMotionEvent(ev);
diff --git a/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java b/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java
index fde220cbf..b6fcdf414 100644
--- a/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java
+++ b/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java
@@ -54,7 +54,7 @@ public class ViewGroupFocusHelper extends FocusIndicatorHelper {
outRect.left += child.getX();
outRect.top += child.getY();
- if (parent != mContainer) {
+ if (parent != null && parent != mContainer) {
if (parent instanceof PagedView) {
PagedView page = (PagedView) parent;
outRect.left -= page.getScrollForPage(page.indexOfChild(child));
diff --git a/src/com/android/launcher3/lineage/LineageLauncher.java b/src/com/android/launcher3/lineage/LineageLauncher.java
new file mode 100644
index 000000000..f8aedccc7
--- /dev/null
+++ b/src/com/android/launcher3/lineage/LineageLauncher.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 The LineageOS 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.lineage;
+
+import com.android.launcher3.Launcher;
+
+public class LineageLauncher extends Launcher {
+
+ private final LineageLauncherCallbacks mCallbacks;
+
+ public LineageLauncher() {
+ mCallbacks = new LineageLauncherCallbacks(this);
+ setLauncherCallbacks(mCallbacks);
+ }
+
+ public LineageLauncherCallbacks getCallbacks() {
+ return mCallbacks;
+ }
+}
diff --git a/src/com/android/launcher3/lineage/LineageLauncherCallbacks.java b/src/com/android/launcher3/lineage/LineageLauncherCallbacks.java
new file mode 100644
index 000000000..b7e662bb4
--- /dev/null
+++ b/src/com/android/launcher3/lineage/LineageLauncherCallbacks.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2018 The LineageOS 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.lineage;
+
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.os.Bundle;
+import android.os.Handler;
+
+import com.android.launcher3.AppInfo;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherCallbacks;
+import com.android.launcher3.Utilities;
+
+import com.google.android.libraries.gsa.launcherclient.LauncherClient;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+public class LineageLauncherCallbacks implements LauncherCallbacks,
+ OnSharedPreferenceChangeListener, OnDeviceProfileChangeListener {
+ public static final String KEY_ENABLE_MINUS_ONE = "pref_enable_minus_one";
+ public static final String SEARCH_PACKAGE = "com.google.android.googlequicksearchbox";
+
+ private final LineageLauncher mLauncher;
+
+ private OverlayCallbackImpl mOverlayCallbacks;
+ private LauncherClient mLauncherClient;
+ private boolean mDeferCallbacks;
+
+ public LineageLauncherCallbacks(LineageLauncher launcher) {
+ mLauncher = launcher;
+ }
+
+ public void deferCallbacksUntilNextResumeOrStop() {
+ mDeferCallbacks = true;
+ }
+
+ public LauncherClient getLauncherClient() {
+ return mLauncherClient;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ SharedPreferences prefs = Utilities.getPrefs(mLauncher);
+ mOverlayCallbacks = new OverlayCallbackImpl(mLauncher);
+ mLauncherClient = new LauncherClient(mLauncher, mOverlayCallbacks, getClientOptions(prefs));
+ mOverlayCallbacks.setClient(mLauncherClient);
+ prefs.registerOnSharedPreferenceChangeListener(this);
+
+ mLauncher.addOnDeviceProfileChangeListener(this);
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ mLauncherClient.onDetachedFromWindow();
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ mLauncherClient.onAttachedToWindow();
+ }
+
+ @Override
+ public void onHomeIntent(boolean internalStateHandled) {
+ mLauncherClient.hideOverlay(mLauncher.isStarted() && !mLauncher.isForceInvisible());
+ }
+
+ @Override
+ public void onResume() {
+ Handler handler = mLauncher.getDragLayer().getHandler();
+ if (mDeferCallbacks) {
+ if (handler == null) {
+ // Finish defer if we are not attached to window.
+ checkIfStillDeferred();
+ } else {
+ // Wait one frame before checking as we can get multiple resume-pause events
+ // in the same frame.
+ handler.post(this::checkIfStillDeferred);
+ }
+ } else {
+ mLauncherClient.onResume();
+ }
+
+ }
+
+ @Override
+ public void onPause() {
+ if (!mDeferCallbacks) {
+ mLauncherClient.onPause();
+ }
+ }
+
+ @Override
+ public void onStart() {
+ if (!mDeferCallbacks) {
+ mLauncherClient.onStart();
+ }
+ }
+
+ @Override
+ public void onStop() {
+ if (mDeferCallbacks) {
+ checkIfStillDeferred();
+ } else {
+ mLauncherClient.onStop();
+ }
+ }
+
+ @Override
+ public void onDeviceProfileChanged(DeviceProfile dp) {
+ mLauncherClient.reattachOverlay();
+ }
+
+ private void checkIfStillDeferred() {
+ if (!mDeferCallbacks) {
+ return;
+ }
+ if (!mLauncher.hasBeenResumed() && mLauncher.isStarted()) {
+ return;
+ }
+ mDeferCallbacks = false;
+
+ // Move the client to the correct state. Calling the same method twice is no-op.
+ if (mLauncher.isStarted()) {
+ mLauncherClient.onStart();
+ }
+ if (mLauncher.hasBeenResumed()) {
+ mLauncherClient.onResume();
+ } else {
+ mLauncherClient.onPause();
+ }
+ if (!mLauncher.isStarted()) {
+ mLauncherClient.onStop();
+ }
+ }
+ @Override
+ public void onDestroy() {
+ mLauncherClient.onDestroy();
+ Utilities.getPrefs(mLauncher).unregisterOnSharedPreferenceChangeListener(this);
+ }
+
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
+ if (KEY_ENABLE_MINUS_ONE.equals(key)) {
+ mLauncherClient.setClientOptions(getClientOptions(prefs));
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) { }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) { }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { }
+
+ @Override
+ public void dump(String prefix, FileDescriptor fd, PrintWriter w, String[] args) {
+ mLauncherClient.dump(prefix, w);
+ }
+
+ @Override
+ public boolean handleBackPressed() {
+ return false;
+ }
+
+ @Override
+ public void onTrimMemory(int level) { }
+
+ @Override
+ public void onLauncherProviderChange() { }
+
+ @Override
+ public boolean startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchData) {
+ return false;
+ }
+
+ private LauncherClient.ClientOptions getClientOptions(SharedPreferences prefs) {
+ return new LauncherClient.ClientOptions(
+ prefs.getBoolean(KEY_ENABLE_MINUS_ONE, true),
+ true, /* enableHotword */
+ true /* enablePrewarming */
+ );
+ }
+}
diff --git a/src/com/android/launcher3/lineage/LineageUtils.java b/src/com/android/launcher3/lineage/LineageUtils.java
new file mode 100644
index 000000000..75a9252dd
--- /dev/null
+++ b/src/com/android/launcher3/lineage/LineageUtils.java
@@ -0,0 +1,78 @@
+package com.android.launcher3.lineage;
+
+import android.app.KeyguardManager;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.hardware.biometrics.BiometricPrompt;
+import android.os.CancellationSignal;
+import android.os.Handler;
+import android.os.Looper;
+import android.widget.Toast;
+
+import com.android.launcher3.R;
+
+public class LineageUtils {
+
+ /**
+ * Shows authentication screen to confirm credentials (pin, pattern or password) for the current
+ * user of the device.
+ *
+ * @param context The {@code Context} used to get {@code KeyguardManager} service
+ * @param title the {@code String} which will be shown as the pompt title
+ * @param successRunnable The {@code Runnable} which will be executed if the user does not setup
+ * device security or if lock screen is unlocked
+ */
+ public static void showLockScreen(Context context, String title, Runnable successRunnable) {
+ if (hasSecureKeyguard(context)) {
+ final BiometricPrompt.AuthenticationCallback authenticationCallback =
+ new BiometricPrompt.AuthenticationCallback() {
+ @Override
+ public void onAuthenticationSucceeded(
+ BiometricPrompt.AuthenticationResult result) {
+ successRunnable.run();
+ }
+
+ @Override
+ public void onAuthenticationError(int errorCode, CharSequence errString) {
+ //Do nothing
+ }
+ };
+
+ final BiometricPrompt.Builder builder = new BiometricPrompt.Builder(context)
+ .setTitle(title);
+
+ final KeyguardManager keyguardManager = context.getSystemService(KeyguardManager.class);
+
+ if (keyguardManager.isDeviceSecure()) {
+ builder.setDeviceCredentialAllowed(true);
+ }
+
+ final BiometricPrompt bp = builder.build();
+ final Handler handler = new Handler(Looper.getMainLooper());
+ bp.authenticate(new CancellationSignal(),
+ runnable -> handler.post(runnable),
+ authenticationCallback);
+ } else {
+ // Notify the user a secure keyguard is required for protected apps,
+ // but allow to set hidden apps
+ Toast.makeText(context, R.string.trust_apps_no_lock_error, Toast.LENGTH_LONG)
+ .show();
+ successRunnable.run();
+ }
+ }
+
+ public static boolean hasSecureKeyguard(Context context) {
+ final KeyguardManager keyguardManager = context.getSystemService(KeyguardManager.class);
+ return keyguardManager != null && keyguardManager.isKeyguardSecure();
+ }
+
+ public static boolean hasPackageInstalled(Context context, String pkgName) {
+ try {
+ ApplicationInfo ai = context.getPackageManager().getApplicationInfo(pkgName, 0);
+ return ai.enabled;
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ }
+}
diff --git a/src/com/android/launcher3/lineage/OverlayCallbackImpl.java b/src/com/android/launcher3/lineage/OverlayCallbackImpl.java
new file mode 100644
index 000000000..d0d6756a4
--- /dev/null
+++ b/src/com/android/launcher3/lineage/OverlayCallbackImpl.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2016 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.lineage;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.Launcher.LauncherOverlay;
+import com.android.launcher3.Launcher.LauncherOverlayCallbacks;
+import com.google.android.libraries.gsa.launcherclient.LauncherClient;
+import com.google.android.libraries.gsa.launcherclient.LauncherClientCallbacks;
+
+/**
+ * Implements {@link LauncherOverlay} and passes all the corresponding events to {@link
+ * LauncherClient}. {@see setClient}
+ *
+ * <p>Implements {@link LauncherClientCallbacks} and sends all the corresponding callbacks to {@link
+ * Launcher}.
+ */
+public class OverlayCallbackImpl implements LauncherOverlay, LauncherClientCallbacks {
+ private final Launcher mLauncher;
+
+ private LauncherClient mClient;
+ private LauncherOverlayCallbacks mLauncherOverlayCallbacks;
+ private boolean mWasOverlayAttached = false;
+
+ public OverlayCallbackImpl(Launcher launcher) {
+ mLauncher = launcher;
+ }
+
+ public void setClient(LauncherClient client) {
+ mClient = client;
+ }
+
+ @Override
+ public void onServiceStateChanged(boolean overlayAttached, boolean hotwordActive) {
+ if (overlayAttached != mWasOverlayAttached) {
+ mWasOverlayAttached = overlayAttached;
+ mLauncher.setLauncherOverlay(overlayAttached ? this : null);
+ }
+ }
+
+ @Override
+ public void onOverlayScrollChanged(float progress) {
+ if (mLauncherOverlayCallbacks != null) {
+ mLauncherOverlayCallbacks.onScrollChanged(progress);
+ }
+ }
+
+ @Override
+ public void onScrollInteractionBegin() {
+ mClient.startMove();
+ }
+
+ @Override
+ public void onScrollInteractionEnd() {
+ mClient.endMove();
+ }
+
+ @Override
+ public void onScrollChange(float progress, boolean rtl) {
+ mClient.updateMove(progress);
+ }
+
+ @Override
+ public void setOverlayCallbacks(Launcher.LauncherOverlayCallbacks callbacks) {
+ mLauncherOverlayCallbacks = callbacks;
+ }
+}
diff --git a/src/com/android/launcher3/lineage/trust/HiddenAppsFilter.java b/src/com/android/launcher3/lineage/trust/HiddenAppsFilter.java
new file mode 100644
index 000000000..942887693
--- /dev/null
+++ b/src/com/android/launcher3/lineage/trust/HiddenAppsFilter.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 The LineageOS 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.lineage.trust;
+
+import android.content.ComponentName;
+import android.content.Context;
+
+import com.android.launcher3.AppFilter;
+import com.android.launcher3.lineage.trust.db.TrustDatabaseHelper;
+
+@SuppressWarnings("unused")
+public class HiddenAppsFilter extends AppFilter {
+ private TrustDatabaseHelper mDbHelper;
+
+ public HiddenAppsFilter(Context context) {
+ if (context == null) {
+ throw new IllegalArgumentException("Context must not be null!");
+ }
+
+ mDbHelper = TrustDatabaseHelper.getInstance(context);
+ }
+
+ @Override
+ public boolean shouldShowApp(ComponentName app) {
+ return !mDbHelper.isPackageHidden(app.getPackageName());
+ }
+}
diff --git a/src/com/android/launcher3/lineage/trust/LoadTrustComponentsTask.java b/src/com/android/launcher3/lineage/trust/LoadTrustComponentsTask.java
new file mode 100644
index 000000000..bf0a08d49
--- /dev/null
+++ b/src/com/android/launcher3/lineage/trust/LoadTrustComponentsTask.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2019 The LineageOS 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.lineage.trust;
+
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.graphics.drawable.Drawable;
+import android.os.AsyncTask;
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+
+import com.android.launcher3.lineage.trust.db.TrustComponent;
+import com.android.launcher3.lineage.trust.db.TrustDatabaseHelper;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class LoadTrustComponentsTask extends AsyncTask<Void, Integer, List<TrustComponent>> {
+ @NonNull
+ private TrustDatabaseHelper mDbHelper;
+
+ @NonNull
+ private PackageManager mPackageManager;
+
+ @NonNull
+ private Callback mCallback;
+
+ LoadTrustComponentsTask(@NonNull TrustDatabaseHelper dbHelper,
+ @NonNull PackageManager packageManager,
+ @NonNull Callback callback) {
+ mDbHelper = dbHelper;
+ mPackageManager = packageManager;
+ mCallback = callback;
+ }
+
+ @Override
+ protected List<TrustComponent> doInBackground(Void... voids) {
+ List<TrustComponent> list = new ArrayList<>();
+
+ Intent filter = new Intent(Intent.ACTION_MAIN, null);
+ filter.addCategory(Intent.CATEGORY_LAUNCHER);
+
+ List<ResolveInfo> apps = mPackageManager.queryIntentActivities(filter,
+ PackageManager.GET_META_DATA);
+
+ int numPackages = apps.size();
+ for (int i = 0; i < numPackages; i++) {
+ ResolveInfo app = apps.get(i);
+ try {
+ String pkgName = app.activityInfo.packageName;
+ String label = mPackageManager.getApplicationLabel(
+ mPackageManager.getApplicationInfo(pkgName,
+ PackageManager.GET_META_DATA)).toString();
+ Drawable icon = app.loadIcon(mPackageManager);
+ boolean isHidden = mDbHelper.isPackageHidden(pkgName);
+ boolean isProtected = mDbHelper.isPackageProtected(pkgName);
+
+ list.add(new TrustComponent(pkgName, icon, label, isHidden, isProtected));
+
+ publishProgress(Math.round(i * 100f / numPackages));
+ } catch (PackageManager.NameNotFoundException ignored) {
+ }
+ }
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ Collections.sort(list, (a, b) -> a.getLabel().compareTo(b.getLabel()));
+ }
+
+ return list;
+ }
+
+ @Override
+ protected void onProgressUpdate(Integer... values) {
+ if (values.length > 0) {
+ mCallback.onLoadListProgress(values[0]);
+ }
+ }
+
+ @Override
+ protected void onPostExecute(List<TrustComponent> trustComponents) {
+ mCallback.onLoadCompleted(trustComponents);
+ }
+
+ interface Callback {
+ void onLoadListProgress(int progress);
+ void onLoadCompleted(List<TrustComponent> result);
+ }
+}
diff --git a/src/com/android/launcher3/lineage/trust/TrustAppsActivity.java b/src/com/android/launcher3/lineage/trust/TrustAppsActivity.java
new file mode 100644
index 000000000..61bcc7910
--- /dev/null
+++ b/src/com/android/launcher3/lineage/trust/TrustAppsActivity.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2019 The LineageOS 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.lineage.trust;
+
+import android.app.ActionBar;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.DefaultItemAnimator;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.lineage.LineageUtils;
+import com.android.launcher3.lineage.trust.db.TrustComponent;
+import com.android.launcher3.lineage.trust.db.TrustDatabaseHelper;
+
+import java.util.List;
+
+import static com.android.launcher3.lineage.trust.db.TrustComponent.Kind.HIDDEN;
+import static com.android.launcher3.lineage.trust.db.TrustComponent.Kind.PROTECTED;
+
+public class TrustAppsActivity extends Activity implements
+ TrustAppsAdapter.Listener,
+ LoadTrustComponentsTask.Callback,
+ UpdateItemTask.UpdateCallback {
+
+ private static final String KEY_TRUST_ONBOARDING = "pref_trust_onboarding";
+
+ private RecyclerView mRecyclerView;
+ private LinearLayout mLoadingView;
+ private ProgressBar mProgressBar;
+
+ private TrustDatabaseHelper mDbHelper;
+ private TrustAppsAdapter mAdapter;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstance) {
+ super.onCreate(savedInstance);
+
+ ActionBar actionBar = getActionBar();
+ if (actionBar != null) {
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ }
+
+ setContentView(R.layout.activity_hidden_apps);
+ mRecyclerView = findViewById(R.id.hidden_apps_list);
+ mLoadingView = findViewById(R.id.hidden_apps_loading);
+ mLoadingView.setVisibility(View.VISIBLE);
+ mProgressBar = findViewById(R.id.hidden_apps_progress_bar);
+
+ final boolean hasSecureKeyguard = LineageUtils.hasSecureKeyguard(this);
+ mAdapter = new TrustAppsAdapter(this, hasSecureKeyguard);
+ mDbHelper = TrustDatabaseHelper.getInstance(this);
+
+ mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
+ mRecyclerView.setItemAnimator(new DefaultItemAnimator());
+ mRecyclerView.setAdapter(mAdapter);
+
+ showOnBoarding(false);
+
+ new LoadTrustComponentsTask(mDbHelper, getPackageManager(), this).execute();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ MenuInflater menuInflater = getMenuInflater();
+ menuInflater.inflate(R.menu.menu_trust_apps, menu);
+ return super.onCreateOptionsMenu(menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ int id = item.getItemId();
+ if (id == android.R.id.home) {
+ finish();
+ return true;
+ } else if (id == R.id.menu_trust_help) {
+ showOnBoarding(true);
+ return true;
+ } else {
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ @Override
+ public void onHiddenItemChanged(@NonNull TrustComponent component) {
+ new UpdateItemTask(mDbHelper, this, HIDDEN).execute(component);
+ }
+
+ @Override
+ public void onProtectedItemChanged(@NonNull TrustComponent component) {
+ new UpdateItemTask(mDbHelper, this, PROTECTED).execute(component);
+ }
+
+ @Override
+ public void onUpdated(boolean result) {
+ LauncherAppState state = LauncherAppState.getInstanceNoCreate();
+ if (state != null) {
+ state.getModel().forceReload();
+ }
+ }
+
+ @Override
+ public void onLoadListProgress(int progress) {
+ mProgressBar.setProgress(progress);
+ }
+
+ @Override
+ public void onLoadCompleted(List<TrustComponent> result) {
+ mLoadingView.setVisibility(View.GONE);
+ mRecyclerView.setVisibility(View.VISIBLE);
+ mAdapter.update(result);
+ }
+
+ private void showOnBoarding(boolean forceShow) {
+ SharedPreferences preferenceManager = Utilities.getPrefs(this);
+ if (!forceShow && preferenceManager.getBoolean(KEY_TRUST_ONBOARDING, false)) {
+ return;
+ }
+
+ preferenceManager.edit()
+ .putBoolean(KEY_TRUST_ONBOARDING, true)
+ .apply();
+
+ new AlertDialog.Builder(this)
+ .setView(R.layout.dialog_trust_welcome)
+ .setPositiveButton(android.R.string.ok, null)
+ .show();
+ }
+}
diff --git a/src/com/android/launcher3/lineage/trust/TrustAppsAdapter.java b/src/com/android/launcher3/lineage/trust/TrustAppsAdapter.java
new file mode 100644
index 000000000..6b827d6e1
--- /dev/null
+++ b/src/com/android/launcher3/lineage/trust/TrustAppsAdapter.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2019 The LineageOS 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.lineage.trust;
+
+import android.graphics.drawable.Animatable2;
+import android.graphics.drawable.AnimatedVectorDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.DiffUtil;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.launcher3.R;
+import com.android.launcher3.lineage.trust.db.TrustComponent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+class TrustAppsAdapter extends RecyclerView.Adapter<TrustAppsAdapter.ViewHolder> {
+ private List<TrustComponent> mList = new ArrayList<>();
+ private Listener mListener;
+ private boolean mHasSecureKeyguard;
+
+ TrustAppsAdapter(Listener listener, boolean hasSecureKeyguard) {
+ mListener = listener;
+ mHasSecureKeyguard = hasSecureKeyguard;
+ }
+
+ public void update(List<TrustComponent> list) {
+ DiffUtil.DiffResult result = DiffUtil.calculateDiff(new Callback(mList, list));
+ mList = list;
+ result.dispatchUpdatesTo(this);
+ }
+
+ @NonNull
+ @Override
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int type) {
+ return new ViewHolder(LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.item_hidden_app, parent, false));
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull ViewHolder viewHolder, int i) {
+ viewHolder.bind(mList.get(i), mHasSecureKeyguard);
+ }
+
+ @Override
+ public int getItemCount() {
+ return mList.size();
+ }
+
+ public interface Listener {
+ void onHiddenItemChanged(@NonNull TrustComponent component);
+
+ void onProtectedItemChanged(@NonNull TrustComponent component);
+ }
+
+ class ViewHolder extends RecyclerView.ViewHolder {
+ private ImageView mIconView;
+ private TextView mLabelView;
+ private ImageView mHiddenView;
+ private ImageView mProtectedView;
+
+ ViewHolder(@NonNull View itemView) {
+ super(itemView);
+
+ mIconView = itemView.findViewById(R.id.item_hidden_app_icon);
+ mLabelView = itemView.findViewById(R.id.item_hidden_app_title);
+ mHiddenView = itemView.findViewById(R.id.item_hidden_app_switch);
+ mProtectedView = itemView.findViewById(R.id.item_protected_app_switch);
+ }
+
+ void bind(TrustComponent component, boolean hasSecureKeyguard) {
+ mIconView.setImageDrawable(component.getIcon());
+ mLabelView.setText(component.getLabel());
+
+ mHiddenView.setImageResource(component.isHidden() ?
+ R.drawable.ic_hidden_locked : R.drawable.ic_hidden_unlocked);
+ mProtectedView.setImageResource(component.isProtected() ?
+ R.drawable.ic_protected_locked : R.drawable.ic_protected_unlocked);
+
+ mProtectedView.setVisibility(hasSecureKeyguard ? View.VISIBLE : View.GONE);
+
+ mHiddenView.setOnClickListener(v -> {
+ component.invertVisibility();
+
+ mHiddenView.setImageResource(component.isHidden() ?
+ R.drawable.avd_hidden_lock : R.drawable.avd_hidden_unlock);
+ AnimatedVectorDrawable avd = (AnimatedVectorDrawable) mHiddenView.getDrawable();
+
+ int position = getAdapterPosition();
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
+ avd.registerAnimationCallback(new Animatable2.AnimationCallback() {
+ @Override
+ public void onAnimationEnd(Drawable drawable) {
+ updateHiddenList(position, component);
+ }
+ });
+ avd.start();
+ } else {
+ avd.start();
+ updateHiddenList(position, component);
+ }
+ });
+
+ mProtectedView.setOnClickListener(v -> {
+ component.invertProtection();
+
+ mProtectedView.setImageResource(component.isProtected() ?
+ R.drawable.avd_protected_lock : R.drawable.avd_protected_unlock);
+ AnimatedVectorDrawable avd = (AnimatedVectorDrawable) mProtectedView.getDrawable();
+
+ int position = getAdapterPosition();
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
+ avd.registerAnimationCallback(new Animatable2.AnimationCallback() {
+ @Override
+ public void onAnimationEnd(Drawable drawable) {
+ updateProtectedList(position, component);
+ }
+ });
+ avd.start();
+ } else {
+ avd.start();
+ updateProtectedList(position, component);
+ }
+ });
+ }
+
+ private void updateHiddenList(int position, TrustComponent component) {
+ mListener.onHiddenItemChanged(component);
+ updateList(position, component);
+ }
+
+ private void updateProtectedList(int position, TrustComponent component) {
+ mListener.onProtectedItemChanged(component);
+ updateList(position, component);
+ }
+
+ private void updateList(int position, TrustComponent component) {
+ mList.set(position, component);
+ notifyItemChanged(position);
+ }
+ }
+
+ private static class Callback extends DiffUtil.Callback {
+ List<TrustComponent> mOldList;
+ List<TrustComponent> mNewList;
+
+ public Callback(List<TrustComponent> oldList,
+ List<TrustComponent> newList) {
+ mOldList = oldList;
+ mNewList = newList;
+ }
+
+
+ @Override
+ public int getOldListSize() {
+ return mOldList.size();
+ }
+
+ @Override
+ public int getNewListSize() {
+ return mNewList.size();
+ }
+
+ @Override
+ public boolean areItemsTheSame(int iOld, int iNew) {
+ String oldPkg = mOldList.get(iOld).getPackageName();
+ String newPkg = mNewList.get(iNew).getPackageName();
+ return oldPkg.equals(newPkg);
+ }
+
+ @Override
+ public boolean areContentsTheSame(int iOld, int iNew) {
+ return mOldList.get(iOld).equals(mNewList.get(iNew));
+ }
+ }
+}
diff --git a/src/com/android/launcher3/lineage/trust/UpdateItemTask.java b/src/com/android/launcher3/lineage/trust/UpdateItemTask.java
new file mode 100644
index 000000000..26ae24c6c
--- /dev/null
+++ b/src/com/android/launcher3/lineage/trust/UpdateItemTask.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2019 The LineageOS 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.lineage.trust;
+
+import android.os.AsyncTask;
+import androidx.annotation.NonNull;
+
+import com.android.launcher3.lineage.trust.db.TrustComponent;
+import com.android.launcher3.lineage.trust.db.TrustDatabaseHelper;
+
+public class UpdateItemTask extends AsyncTask<TrustComponent, Void, Boolean> {
+ @NonNull
+ private TrustDatabaseHelper mDbHelper;
+ @NonNull
+ private UpdateCallback mCallback;
+ @NonNull
+ private TrustComponent.Kind mKind;
+
+ UpdateItemTask(@NonNull TrustDatabaseHelper dbHelper,
+ @NonNull UpdateCallback callback,
+ @NonNull TrustComponent.Kind kind) {
+ mDbHelper = dbHelper;
+ mCallback = callback;
+ mKind = kind;
+ }
+
+ @Override
+ protected Boolean doInBackground(TrustComponent... trustComponents) {
+ if (trustComponents.length < 1) {
+ return false;
+ }
+
+ TrustComponent component = trustComponents[0];
+ String pkgName = component.getPackageName();
+
+ switch (mKind) {
+ case HIDDEN:
+ if (component.isHidden()) {
+ mDbHelper.addHiddenApp(pkgName);
+ } else {
+ mDbHelper.removeHiddenApp(pkgName);
+ }
+ break;
+ case PROTECTED:
+ if (component.isProtected()) {
+ mDbHelper.addProtectedApp(pkgName);
+ } else {
+ mDbHelper.removeProtectedApp(pkgName);
+ }
+ break;
+ }
+ return true;
+ }
+
+ @Override
+ protected void onPostExecute(Boolean result) {
+ mCallback.onUpdated(result);
+ }
+
+ interface UpdateCallback {
+ void onUpdated(boolean result);
+ }
+}
diff --git a/src/com/android/launcher3/lineage/trust/db/TrustComponent.java b/src/com/android/launcher3/lineage/trust/db/TrustComponent.java
new file mode 100644
index 000000000..5342bde3d
--- /dev/null
+++ b/src/com/android/launcher3/lineage/trust/db/TrustComponent.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2019 The LineageOS 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.lineage.trust.db;
+
+import android.graphics.drawable.Drawable;
+import androidx.annotation.NonNull;
+
+public class TrustComponent {
+ @NonNull
+ private final String mPackageName;
+ @NonNull
+ private final Drawable mIcon;
+ @NonNull
+ private final String mLabel;
+
+ private boolean mIsHidden;
+ private boolean mIsProtected;
+
+ public TrustComponent(@NonNull String packageName, @NonNull Drawable icon,
+ @NonNull String label, boolean isHidden, boolean isProtected) {
+ mPackageName = packageName;
+ mIcon = icon;
+ mLabel = label;
+ mIsHidden = isHidden;
+ mIsProtected = isProtected;
+ }
+
+ @NonNull
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ @NonNull
+ public Drawable getIcon() {
+ return mIcon;
+ }
+
+ @NonNull
+ public String getLabel() {
+ return mLabel;
+ }
+
+ public boolean isHidden() {
+ return mIsHidden;
+ }
+
+ public boolean isProtected() {
+ return mIsProtected;
+ }
+
+ public void invertVisibility() {
+ mIsHidden = !mIsHidden;
+ }
+
+ public void invertProtection() {
+ mIsProtected = !mIsProtected;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof TrustComponent)) {
+ return false;
+ }
+
+ TrustComponent otherComponent = (TrustComponent) other;
+ return otherComponent.getPackageName().equals(mPackageName) &&
+ otherComponent.isHidden() == mIsHidden;
+ }
+
+ @Override
+ public int hashCode() {
+ return mPackageName.hashCode() + (mIsHidden ? 1 : 0);
+ }
+
+ public enum Kind {
+ HIDDEN,
+ PROTECTED,
+ }
+}
diff --git a/src/com/android/launcher3/lineage/trust/db/TrustDatabaseHelper.java b/src/com/android/launcher3/lineage/trust/db/TrustDatabaseHelper.java
new file mode 100644
index 000000000..715355c8c
--- /dev/null
+++ b/src/com/android/launcher3/lineage/trust/db/TrustDatabaseHelper.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2019 The LineageOS 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.lineage.trust.db;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+public class TrustDatabaseHelper extends SQLiteOpenHelper {
+ private static final int DATABASE_VERSION = 1;
+ private static final String DATABASE_NAME = "trust_apps_db";
+
+ private static final String TABLE_NAME = "trust_apps";
+ private static final String KEY_UID = "uid";
+ private static final String KEY_PKGNAME = "pkgname";
+ private static final String KEY_HIDDEN = "hidden";
+ private static final String KEY_PROTECTED = "protected";
+
+ @Nullable
+ private static TrustDatabaseHelper sSingleton;
+
+ private TrustDatabaseHelper(@NonNull Context context) {
+ super(context, DATABASE_NAME, null, DATABASE_VERSION);
+ }
+
+ public static synchronized TrustDatabaseHelper getInstance(@NonNull Context context) {
+ if (sSingleton == null) {
+ sSingleton = new TrustDatabaseHelper(context);
+ }
+
+ return sSingleton;
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ String CMD_CREATE_TABLE = "CREATE TABLE " + TABLE_NAME +
+ "(" +
+ KEY_UID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
+ KEY_PKGNAME + " TEXT," +
+ KEY_HIDDEN + " INTEGER DEFAULT 0," +
+ KEY_PROTECTED + " INTEGER DEFAULT 0" +
+ ")";
+ db.execSQL(CMD_CREATE_TABLE);
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ }
+
+ public void addHiddenApp(@NonNull String packageName) {
+ if (isPackageHidden(packageName)) {
+ return;
+ }
+
+ SQLiteDatabase db = getWritableDatabase();
+ db.beginTransaction();
+
+ try {
+ ContentValues values = new ContentValues();
+ values.put(KEY_PKGNAME, packageName);
+ values.put(KEY_HIDDEN, 1);
+
+ int rows = db.update(TABLE_NAME, values, KEY_PKGNAME + " = ?", new String[]{KEY_PKGNAME});
+ if (rows != 1) {
+ // Entry doesn't exist, create a new one
+ db.insertOrThrow(TABLE_NAME, null, values);
+ }
+ db.setTransactionSuccessful();
+ } catch (Exception e) {
+ // Ignored
+ } finally {
+ db.endTransaction();
+ }
+ }
+
+ public void addProtectedApp(@NonNull String packageName) {
+ if (isPackageProtected(packageName)) {
+ return;
+ }
+
+ SQLiteDatabase db = getWritableDatabase();
+ db.beginTransaction();
+
+ try {
+ ContentValues values = new ContentValues();
+ values.put(KEY_PKGNAME, packageName);
+ values.put(KEY_PROTECTED, 1);
+
+ int rows = db.update(TABLE_NAME, values, KEY_PKGNAME + " = ?", new String[]{KEY_PKGNAME});
+ if (rows != 1) {
+ // Entry doesn't exist, create a new one
+ db.insertOrThrow(TABLE_NAME, null, values);
+ }
+ db.setTransactionSuccessful();
+ } catch (Exception e) {
+ // Ignored
+ } finally {
+ db.endTransaction();
+ }
+ }
+
+
+ public void removeHiddenApp(@NonNull String packageName) {
+ if (!isPackageHidden(packageName)) {
+ return;
+ }
+
+ SQLiteDatabase db = getWritableDatabase();
+ db.beginTransaction();
+
+ try {
+ ContentValues values = new ContentValues();
+ values.put(KEY_HIDDEN, 0);
+
+ db.update(TABLE_NAME, values, KEY_PKGNAME + " = ?", new String[]{packageName});
+ db.setTransactionSuccessful();
+ } catch (Exception e) {
+ // Ignored
+ } finally {
+ db.endTransaction();
+ }
+ }
+
+ public void removeProtectedApp(@NonNull String packageName) {
+ if (!isPackageProtected(packageName)) {
+ return;
+ }
+
+ SQLiteDatabase db = getWritableDatabase();
+ db.beginTransaction();
+
+ try {
+ ContentValues values = new ContentValues();
+ values.put(KEY_PROTECTED, 0);
+
+ db.update(TABLE_NAME, values, KEY_PKGNAME + " = ?", new String[]{packageName});
+ db.setTransactionSuccessful();
+ } catch (Exception e) {
+ // Ignored
+ } finally {
+ db.endTransaction();
+ }
+ }
+
+ public boolean isPackageHidden(@NonNull String packageName) {
+ String query = String.format("SELECT * FROM %s WHERE %s = ? AND %s = ?", TABLE_NAME, KEY_PKGNAME, KEY_HIDDEN);
+ SQLiteDatabase db = getReadableDatabase();
+ Cursor cursor = db.rawQuery(query, new String[]{packageName, String.valueOf(1)});
+ boolean result = false;
+ try {
+ result = cursor.getCount() != 0;
+ } catch (Exception e) {
+ // Ignored
+ } finally {
+ if (cursor != null && !cursor.isClosed()) {
+ cursor.close();
+ }
+ }
+
+ return result;
+ }
+
+ public boolean isPackageProtected(@NonNull String packageName) {
+ String query = String.format("SELECT * FROM %s WHERE %s = ? AND %s = ?", TABLE_NAME, KEY_PKGNAME, KEY_PROTECTED);
+ SQLiteDatabase db = getReadableDatabase();
+ Cursor cursor = db.rawQuery(query, new String[]{packageName, String.valueOf(1)});
+ boolean result = false;
+ try {
+ result = cursor.getCount() != 0;
+ } catch (Exception e) {
+ // Ignored
+ } finally {
+ if (cursor != null && !cursor.isClosed()) {
+ cursor.close();
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index e8ac1d4c9..817a84c59 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -53,6 +53,7 @@ import com.android.launcher3.ItemInfo;
import com.android.launcher3.ItemInfoWithIcon;
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.dot.DotInfo;
@@ -600,6 +601,8 @@ public class PopupContainerWithArrow extends ArrowPopup implements DragSource,
if (!ItemLongClickListener.canStartDrag(mLauncher)) return false;
// 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();
diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java
index a87b7b897..cad73eb03 100644
--- a/src/com/android/launcher3/popup/SystemShortcut.java
+++ b/src/com/android/launcher3/popup/SystemShortcut.java
@@ -20,6 +20,7 @@ import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
import com.android.launcher3.WorkspaceItemInfo;
+import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.AppLaunchTracker;
import com.android.launcher3.model.WidgetItem;
@@ -135,6 +136,7 @@ public abstract class SystemShortcut<T extends BaseDraggingActivity>
@Override
public View.OnClickListener getOnClickListener(final Launcher launcher,
final ItemInfo itemInfo) {
+ if (!Utilities.isWorkspaceEditAllowed(launcher.getApplicationContext())) return null;
if (itemInfo.getTargetComponent() == null) return null;
final List<WidgetItem> widgets =
launcher.getPopupDataProvider().getWidgetsForPackageUser(new PackageUserKey(
diff --git a/src/com/android/launcher3/provider/ImportDataTask.java b/src/com/android/launcher3/provider/ImportDataTask.java
index 970a03e80..0e080f2a5 100644
--- a/src/com/android/launcher3/provider/ImportDataTask.java
+++ b/src/com/android/launcher3/provider/ImportDataTask.java
@@ -103,7 +103,7 @@ public class ImportDataTask {
String profileId = Long.toString(UserManagerCompat.getInstance(mContext)
.getSerialNumberForUser(Process.myUserHandle()));
- boolean createEmptyRowOnFirstScreen;
+ boolean createEmptyRowOnFirstScreen = false;
if (FeatureFlags.QSB_ON_FIRST_SCREEN) {
try (Cursor c = mContext.getContentResolver().query(mOtherFavoritesUri, null,
// get items on the first row of the first screen (min screen id)
diff --git a/src/com/android/launcher3/qsb/QsbContainerView.java b/src/com/android/launcher3/qsb/QsbContainerView.java
index 0eb428527..3ca340a2b 100644
--- a/src/com/android/launcher3/qsb/QsbContainerView.java
+++ b/src/com/android/launcher3/qsb/QsbContainerView.java
@@ -30,6 +30,8 @@ import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
import android.graphics.Rect;
import android.os.Bundle;
import android.provider.Settings;
@@ -58,6 +60,8 @@ import com.android.launcher3.graphics.FragmentWithPreview;
* AppWidgetManager directly, so that it keeps working in that case.
*/
public class QsbContainerView extends FrameLayout {
+ private static final String QSB_PROVIDER_CLASS
+ = "com.google.android.googlequicksearchbox.SearchWidgetProvider";
public static final String SEARCH_PROVIDER_SETTINGS_KEY = "SEARCH_PROVIDER_PACKAGE_NAME";
@@ -148,6 +152,26 @@ public class QsbContainerView extends FrameLayout {
super.setPadding(left, top, right, bottom);
}
+ public static void updateDefaultLayout(Context context, AppWidgetProviderInfo info) {
+ ComponentName provider = info.provider;
+ if (QSB_PROVIDER_CLASS.equals(provider.getClassName())) {
+ try {
+ ActivityInfo activityInfo =
+ context.getPackageManager().getReceiverInfo(provider,
+ PackageManager.GET_META_DATA);
+ Bundle metaData = activityInfo.metaData;
+ int resId = metaData.getInt(
+ "com.google.android.gsa.searchwidget.alt_initial_layout_cqsb", -1);
+ if (resId != -1) {
+ info.initialLayout = resId;
+ }
+ } catch (Exception e) {
+ // Ignore the exception since if any exceptions happen
+ // the original initialyLayout would be used.
+ }
+ }
+ }
+
/**
* A fragment to display the QSB.
*/
@@ -198,6 +222,11 @@ public class QsbContainerView extends FrameLayout {
return getDefaultView(container, false /* show setup icon */);
}
Bundle opts = createBindOptions();
+ // round quick search bar
+ opts.putString("attached-launcher-identifier",
+ getActivity().getPackageName());
+ opts.putString("requested-widget-style", "cqsb");
+
Context context = getContext();
AppWidgetManager widgetManager = AppWidgetManager.getInstance(context);
diff --git a/src/com/android/launcher3/qsb/QsbWidgetHostView.java b/src/com/android/launcher3/qsb/QsbWidgetHostView.java
index f5ecda3e3..660ff7d7c 100644
--- a/src/com/android/launcher3/qsb/QsbWidgetHostView.java
+++ b/src/com/android/launcher3/qsb/QsbWidgetHostView.java
@@ -16,6 +16,7 @@
package com.android.launcher3.qsb;
+import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
@@ -48,6 +49,11 @@ public class QsbWidgetHostView extends NavigableAppWidgetHostView {
super.updateAppWidget(remoteViews);
}
+ @Override
+ public void setAppWidget(int appWidgetId, AppWidgetProviderInfo info) {
+ QsbContainerView.updateDefaultLayout(getContext(), info);
+ super.setAppWidget(appWidgetId, info);
+ }
public boolean isReinflateRequired(int orientation) {
// Re-inflate is required if the orientation has changed since last inflation.
diff --git a/src/com/android/launcher3/settings/SettingsActivity.java b/src/com/android/launcher3/settings/SettingsActivity.java
index 8d2db78c7..b2520e366 100644
--- a/src/com/android/launcher3/settings/SettingsActivity.java
+++ b/src/com/android/launcher3/settings/SettingsActivity.java
@@ -24,12 +24,10 @@ import static com.android.launcher3.states.RotationHelper.getAllowRotationDefaul
import static com.android.launcher3.util.SecureSettingsObserver.newNotificationSettingsObserver;
import android.app.Activity;
+import android.app.ActivityManager;
import android.app.DialogFragment;
import android.app.Fragment;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
+import android.content.Intent;
import android.os.Bundle;
import android.provider.Settings;
import android.text.TextUtils;
@@ -48,6 +46,9 @@ import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.graphics.GridOptionsProvider;
+import com.android.launcher3.lineage.LineageLauncherCallbacks;
+import com.android.launcher3.lineage.LineageUtils;
+import com.android.launcher3.lineage.trust.TrustAppsActivity;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.util.SecureSettingsObserver;
@@ -55,8 +56,7 @@ import com.android.launcher3.util.SecureSettingsObserver;
* Settings activity for Launcher. Currently implements the following setting: Allow rotation
*/
public class SettingsActivity extends Activity
- implements OnPreferenceStartFragmentCallback, OnPreferenceStartScreenCallback,
- SharedPreferences.OnSharedPreferenceChangeListener{
+ implements OnPreferenceStartFragmentCallback, OnPreferenceStartScreenCallback {
private static final String DEVELOPER_OPTIONS_KEY = "pref_developer_options";
private static final String FLAGS_PREFERENCE_KEY = "flag_toggler";
@@ -70,7 +70,8 @@ public class SettingsActivity extends Activity
private static final int DELAY_HIGHLIGHT_DURATION_MILLIS = 600;
public static final String SAVE_HIGHLIGHTED_KEY = "android:preference_highlighted";
- public static final String GRID_OPTIONS_PREFERENCE_KEY = "pref_grid_options";
+ public static final String KEY_MINUS_ONE = "pref_enable_minus_one";
+ public static final String KEY_TRUST_APPS = "pref_trust_apps";
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -90,28 +91,6 @@ public class SettingsActivity extends Activity
.replace(android.R.id.content, f)
.commit();
}
- Utilities.getPrefs(getApplicationContext()).registerOnSharedPreferenceChangeListener(this);
- }
- @Override
- public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
- if (GRID_OPTIONS_PREFERENCE_KEY.equals(key)) {
-
- final ComponentName cn = new ComponentName(getApplicationContext(),
- GridOptionsProvider.class);
- Context c = getApplicationContext();
- int oldValue = c.getPackageManager().getComponentEnabledSetting(cn);
- int newValue;
- if (Utilities.getPrefs(c).getBoolean(GRID_OPTIONS_PREFERENCE_KEY, false)) {
- newValue = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
- } else {
- newValue = PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
- }
-
- if (oldValue != newValue) {
- c.getPackageManager().setComponentEnabledSetting(cn, newValue,
- PackageManager.DONT_KILL_APP);
- }
- }
}
private boolean startFragment(String fragment, Bundle args, String key) {
@@ -198,6 +177,7 @@ public class SettingsActivity extends Activity
switch (preference.getKey()) {
case NOTIFICATION_DOTS_PREFERENCE_KEY:
if (!Utilities.ATLEAST_OREO ||
+ getContext().getSystemService(ActivityManager.class).isLowRamDevice() ||
!getResources().getBoolean(R.bool.notification_dots_enabled)) {
return false;
}
@@ -233,10 +213,21 @@ public class SettingsActivity extends Activity
// Show if plugins are enabled or flag UI is enabled.
return FeatureFlags.showFlagTogglerUi(getContext()) ||
PluginManagerWrapper.hasPlugins(getContext());
- case GRID_OPTIONS_PREFERENCE_KEY:
- return Utilities.isDevelopersOptionsEnabled(getContext()) &&
- Utilities.IS_DEBUG_DEVICE &&
- Utilities.existsStyleWallpapers(getContext());
+
+ case KEY_MINUS_ONE:
+ return LineageUtils.hasPackageInstalled(getActivity(),
+ LineageLauncherCallbacks.SEARCH_PACKAGE);
+
+ case KEY_TRUST_APPS:
+ preference.setOnPreferenceClickListener(p -> {
+ LineageUtils.showLockScreen(getActivity(),
+ getString(R.string.trust_apps_manager_name), () -> {
+ Intent intent = new Intent(getActivity(), TrustAppsActivity.class);
+ startActivity(intent);
+ });
+ return true;
+ });
+ return true;
}
return true;
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
index 03493a538..918b631bc 100644
--- a/src/com/android/launcher3/touch/ItemClickHandler.java
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -26,6 +26,7 @@ import static com.android.launcher3.model.AppLaunchTracker.CONTAINER_ALL_APPS;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.LauncherApps;
@@ -55,6 +56,7 @@ import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.PackageInstallerCompat;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.lineage.trust.db.TrustDatabaseHelper;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.views.FloatingIconView;
import com.android.launcher3.widget.PendingAppWidgetHostView;
@@ -267,6 +269,15 @@ public class ItemClickHandler {
// Preload the icon to reduce latency b/w swapping the floating view with the original.
FloatingIconView.fetchIcon(launcher, v, item, true /* isOpening */);
}
- launcher.startActivitySafely(v, intent, item, sourceContainer);
+
+ TrustDatabaseHelper db = TrustDatabaseHelper.getInstance(launcher);
+ ComponentName cn = item.getTargetComponent();
+ boolean isProtected = cn != null && db.isPackageProtected(cn.getPackageName());
+
+ if (isProtected) {
+ launcher.startActivitySafelyAuth(v, intent, item, sourceContainer);
+ } else {
+ launcher.startActivitySafely(v, intent, item, sourceContainer);
+ }
}
}
diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java
index e97adb577..78d1d3ca8 100644
--- a/src/com/android/launcher3/util/PackageManagerHelper.java
+++ b/src/com/android/launcher3/util/PackageManagerHelper.java
@@ -175,11 +175,6 @@ public class PackageManagerHelper {
}
}
- public static Intent getStyleWallpapersIntent(Context context) {
- return new Intent(Intent.ACTION_SET_WALLPAPER).setComponent(
- new ComponentName(context.getString(R.string.wallpaper_picker_package),
- "com.android.customization.picker.CustomizationPickerActivity"));
- }
/**
* Starts the details activity for {@code info}
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index 465df448e..c718d74e7 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -18,8 +18,10 @@ package com.android.launcher3.views;
import static com.android.launcher3.Utilities.EXTRA_WALLPAPER_FLAVOR;
import static com.android.launcher3.Utilities.EXTRA_WALLPAPER_OFFSET;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ResolveInfo;
import android.graphics.Rect;
import android.graphics.RectF;
import android.text.TextUtils;
@@ -152,13 +154,13 @@ public class OptionsPopupView extends ArrowPopup
RectF target = new RectF(x - halfSize, y - halfSize, x + halfSize, y + halfSize);
ArrayList<OptionItem> options = new ArrayList<>();
- int resString = Utilities.existsStyleWallpapers(launcher) ?
+ int resString = existsStyleWallpapers(launcher) ?
R.string.styles_wallpaper_button_text : R.string.wallpaper_button_text;
- int resDrawable = Utilities.existsStyleWallpapers(launcher) ?
+ int resDrawable = existsStyleWallpapers(launcher) ?
R.drawable.ic_palette : R.drawable.ic_wallpaper;
options.add(new OptionItem(resString, resDrawable,
ControlType.WALLPAPER_BUTTON, OptionsPopupView::startWallpaperPicker));
- if (!FeatureFlags.GO_DISABLE_WIDGETS) {
+ if (!FeatureFlags.GO_DISABLE_WIDGETS && Utilities.isWorkspaceEditAllowed(launcher)) {
options.add(new OptionItem(R.string.widget_button_text, R.drawable.ic_widget,
ControlType.WIDGETS_BUTTON, OptionsPopupView::onWidgetsClicked));
}
@@ -168,6 +170,14 @@ public class OptionsPopupView extends ArrowPopup
show(launcher, target, options);
}
+ private static boolean existsStyleWallpapers(Launcher launcher) {
+ Intent intent = new Intent(Intent.ACTION_SET_WALLPAPER);
+ intent.setComponent(new ComponentName(launcher.getString(R.string.wallpaper_picker_package),
+ "com.android.customization.picker.CustomizationPickerActivity"));
+ ResolveInfo ri = launcher.getPackageManager().resolveActivity(intent, 0);
+ return ri != null;
+ }
+
public static boolean onWidgetsClicked(View view) {
return openWidgets(Launcher.getLauncher(view.getContext())) != null;
}
@@ -205,10 +215,13 @@ public class OptionsPopupView extends ArrowPopup
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
.putExtra(EXTRA_WALLPAPER_OFFSET,
launcher.getWorkspace().getWallpaperOffsetForCenterPage());
- if (!Utilities.existsStyleWallpapers(launcher)) {
+ if (!existsStyleWallpapers(launcher)) {
intent.putExtra(EXTRA_WALLPAPER_FLAVOR, "wallpaper_only");
} else {
intent.putExtra(EXTRA_WALLPAPER_FLAVOR, "focus_wallpaper");
+ intent.setComponent(new ComponentName(
+ launcher.getString(R.string.wallpaper_picker_package),
+ "com.android.customization.picker.CustomizationPickerActivity"));
}
String pickerPackage = launcher.getString(R.string.wallpaper_picker_package);
if (!TextUtils.isEmpty(pickerPackage)) {