Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 164 additions & 0 deletions quickstep/src/com/android/launcher3/popup/GrapheneSystemShortcut.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
package com.android.launcher3.popup;

import android.Manifest;
import android.app.ActivityOptions;
import android.app.StorageScope;
import android.content.Intent;
import android.content.pm.GosPackageState;
import android.content.pm.GosPackageStateFlag;
import android.ext.cscopes.ContactScopesApi;
import android.ext.micspoofing.MicSpoofingApi;
import android.view.View;
import android.window.SplashScreen;

import androidx.annotation.Nullable;
import androidx.annotation.RequiresPermission;

import com.android.launcher3.BaseActivity;
import com.android.launcher3.R;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.views.ActivityContext;

public interface GrapheneSystemShortcut {

abstract class ScopedFeatureShortcut<T extends ActivityContext> extends SystemShortcut<T> {

protected final String targetPackage;

private ScopedFeatureShortcut(
int iconResId,
int labelResId,
T target,
ItemInfo itemInfo,
View originalView
) {
super(iconResId, labelResId, target, itemInfo, originalView);
targetPackage = itemInfo.getTargetPackage();
}

protected static boolean hasGosPackageStateFlag(ItemInfo itemInfo, int flag) {
String pkg = itemInfo.getTargetPackage();
if (pkg == null) {
return false;
}
return GosPackageState.get(pkg, itemInfo.user).hasFlag(flag);
}

@RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
@Override
public void onClick(View view) {
dismissTaskMenuView();

Intent intent = getIntent(targetPackage);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
var options = ActivityOptions.makeBasic()
.setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR)
.toBundle();
view.getContext().startActivityAsUser(intent, options, mItemInfo.user);
}

protected abstract Intent getIntent(String targetPkg);
}

/**
* Storage
*/

SystemShortcut.Factory<BaseActivity> STORAGE_SCOPES = StorageScopes::maybeGet;

class StorageScopes<T extends ActivityContext> extends ScopedFeatureShortcut<T> {

private StorageScopes(T target, ItemInfo itemInfo, View originalView) {
super(
R.drawable.ic_sscopes_add_file,
R.string.storage_scopes_drop_target_label,
target,
itemInfo,
originalView
);
}

@Nullable
public static <T extends ActivityContext> StorageScopes<T> maybeGet(
T target, ItemInfo itemInfo, View originalView
) {
if (!hasGosPackageStateFlag(itemInfo, GosPackageStateFlag.STORAGE_SCOPES_ENABLED)) {
return null;
}
return new StorageScopes<>(target, itemInfo, originalView);
}

@Override
protected Intent getIntent(String targetPkg) {
return StorageScope.createConfigActivityIntent(targetPkg);
}
}

/**
* Contacts
*/

SystemShortcut.Factory<BaseActivity> CONTACT_SCOPES = ContactScopes::maybeGet;

class ContactScopes<T extends ActivityContext> extends ScopedFeatureShortcut<T> {

private ContactScopes(T target, ItemInfo itemInfo, View originalView) {
super(
R.drawable.ic_cscopes,
R.string.contact_scopes_label,
target,
itemInfo,
originalView
);
}

@Nullable
public static <T extends ActivityContext> ContactScopes<T> maybeGet(
T target, ItemInfo itemInfo, View originalView
) {
if (!hasGosPackageStateFlag(itemInfo, GosPackageStateFlag.CONTACT_SCOPES_ENABLED)) {
return null;
}
return new ContactScopes<>(target, itemInfo, originalView);
}

@Override
protected Intent getIntent(String targetPkg) {
return ContactScopesApi.createConfigActivityIntent(targetPkg);
}
}

/**
* Mic spoofing
*/

SystemShortcut.Factory<BaseActivity> MIC_SPOOFING = MicSpoofing::maybeGet;

class MicSpoofing<T extends ActivityContext> extends ScopedFeatureShortcut<T> {

private MicSpoofing(T target, ItemInfo itemInfo, View originalView) {
super(
R.drawable.ic_microphone_spoofing,
R.string.microphone_spoofing_drop_target_label,
target,
itemInfo,
originalView
);
}

@Nullable
public static <T extends ActivityContext> MicSpoofing<T> maybeGet(
T target, ItemInfo itemInfo, View originalView
) {
if (!hasGosPackageStateFlag(itemInfo, GosPackageStateFlag.MIC_SPOOFING_ENABLED)) {
return null;
}
return new MicSpoofing<>(target, itemInfo, originalView);
}

@Override
protected Intent getIntent(String targetPkg) {
return MicSpoofingApi.createConfigActivityIntent(targetPkg);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,16 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_INTERRUPTED;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_NOT_PINNABLE;
import static com.android.launcher3.popup.QuickstepSystemShortcut.getSplitSelectShortcutByPosition;
import static com.android.launcher3.popup.GrapheneSystemShortcut.CONTACT_SCOPES;
import static com.android.launcher3.popup.GrapheneSystemShortcut.MIC_SPOOFING;
import static com.android.launcher3.popup.GrapheneSystemShortcut.STORAGE_SCOPES;
import static com.android.launcher3.popup.SystemShortcut.ADD_TO_HOME_SCREEN;
import static com.android.launcher3.popup.SystemShortcut.APP_INFO;
import static com.android.launcher3.popup.SystemShortcut.BUBBLE_SHORTCUT;
import static com.android.launcher3.popup.SystemShortcut.CONTACT_SCOPES;
import static com.android.launcher3.popup.SystemShortcut.DONT_SUGGEST_APP;
import static com.android.launcher3.popup.SystemShortcut.INSTALL;
import static com.android.launcher3.popup.SystemShortcut.PRIVATE_PROFILE_INSTALL;
import static com.android.launcher3.popup.SystemShortcut.REMOVE;
import static com.android.launcher3.popup.SystemShortcut.STORAGE_SCOPES;
import static com.android.launcher3.popup.SystemShortcut.UNINSTALL_APP;
import static com.android.launcher3.popup.SystemShortcut.WIDGETS;
import static com.android.launcher3.taskbar.LauncherTaskbarUIController.ALL_APPS_PAGE_PROGRESS_INDEX;
Expand Down Expand Up @@ -551,6 +552,7 @@ public Stream<SystemShortcut.Factory> getSupportedShortcuts(ItemInfo itemInfo) {
shortcuts.add(WIDGETS);
shortcuts.add(STORAGE_SCOPES);
shortcuts.add(CONTACT_SCOPES);
shortcuts.add(MIC_SPOOFING);
shortcuts.add(INSTALL);
// TODO(b/444744861): Update private space apps to have its own container.
boolean isPinnable = itemInfo instanceof ItemInfoWithIcon info
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ public void clearAllActiveState() { }
TaskShortcutFactory.MODAL,
TaskShortcutFactory.STORAGE_SCOPES,
TaskShortcutFactory.CONTACT_SCOPES,
TaskShortcutFactory.MIC_SPOOFING,
};

/**
Expand Down
28 changes: 26 additions & 2 deletions quickstep/src/com/android/quickstep/TaskShortcutFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import com.android.launcher3.R;
import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
import com.android.launcher3.model.WellbeingModel;
import com.android.launcher3.popup.GrapheneSystemShortcut;
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.popup.SystemShortcut.AppInfo;
import com.android.launcher3.util.InstantAppResolver;
Expand Down Expand Up @@ -135,7 +136,8 @@ public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
TaskContainer taskContainer) {
TaskView taskView = taskContainer.getTaskView();

var s = SystemShortcut.StorageScopes.maybeGet(container, taskContainer.getItemInfo(), taskView);
var s = GrapheneSystemShortcut.StorageScopes.maybeGet(
container, taskContainer.getItemInfo(), taskView);
if (s == null) {
return null;
}
Expand All @@ -155,7 +157,29 @@ public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
TaskContainer taskContainer) {
TaskView taskView = taskContainer.getTaskView();

var s = SystemShortcut.ContactScopes.maybeGet(container, taskContainer.getItemInfo(), taskView);
var s = GrapheneSystemShortcut.ContactScopes.maybeGet(
container, taskContainer.getItemInfo(), taskView);
if (s == null) {
return null;
}
return Collections.singletonList(s);
}

@Override
public boolean showForGroupedTask() {
return true;
}
};

TaskShortcutFactory MIC_SPOOFING = new TaskShortcutFactory() {
@Nullable
@Override
public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
TaskContainer taskContainer) {
TaskView taskView = taskContainer.getTaskView();

var s = GrapheneSystemShortcut.MicSpoofing.maybeGet(
container, taskContainer.getItemInfo(), taskView);
if (s == null) {
return null;
}
Expand Down
11 changes: 11 additions & 0 deletions res/drawable/ic_microphone_spoofing.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!-- "mic" from Material Symbols -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?android:attr/colorControlNormal"
android:viewportHeight="960"
android:viewportWidth="960">
<path
android:fillColor="@android:color/white"
android:pathData="M480,560Q447,560 423.5,536.5Q400,513 400,480V240Q400,207 423.5,183.5Q447,160 480,160Q513,160 536.5,183.5Q560,207 560,240V480Q560,513 536.5,536.5Q513,560 480,560ZM440,800V708Q355,688 297.5,620.5Q240,553 240,460H320Q320,527 366.5,573.5Q413,620 480,620Q547,620 593.5,573.5Q640,527 640,460H720Q720,553 662.5,620.5Q605,688 520,708V800H440Z" />
</vector>
2 changes: 2 additions & 0 deletions res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,8 @@
<string name="storage_scopes_drop_target_label">Storage Scopes</string>
<!-- Label for Storage Scopes drop target. [CHAR_LIMIT=20] -->
<string name="contact_scopes_label">Contact Scopes</string>
<!-- Label for Microphone Spoofing drop target. [CHAR_LIMIT=30] -->
<string name="microphone_spoofing_drop_target_label">Microphone Spoofing</string>
<!-- Label for install drop target. [CHAR_LIMIT=20] -->
<string name="install_drop_target_label">Install</string>
<!-- Label for dismiss prediction. -->
Expand Down
5 changes: 1 addition & 4 deletions src/com/android/launcher3/Launcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -2957,10 +2957,7 @@ public Stream<SystemShortcut.Factory> getSupportedShortcuts(ItemInfo itemInfo) {
return Stream.of(APP_INFO, WIDGETS, INSTALL);
}
}
return Stream.of(APP_INFO, WIDGETS, INSTALL
, com.android.launcher3.popup.SystemShortcut.STORAGE_SCOPES
, com.android.launcher3.popup.SystemShortcut.CONTACT_SCOPES
);
return Stream.of(APP_INFO, WIDGETS, INSTALL);
}

/**
Expand Down
84 changes: 0 additions & 84 deletions src/com/android/launcher3/popup/SystemShortcut.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.GosPackageState;
import android.content.pm.GosPackageStateFlag;
import android.content.pm.ShortcutInfo;
import android.graphics.Rect;
import android.os.Process;
Expand All @@ -25,14 +23,12 @@
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.ImageView;
import android.widget.TextView;
import android.window.SplashScreen;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.AbstractFloatingViewHelper;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.DropTargetHandler;
import com.android.launcher3.Flags;
import com.android.launcher3.LauncherSettings;
Expand Down Expand Up @@ -260,86 +256,6 @@ public SplitAccessibilityInfo(boolean containsMultipleTasks,
}
}

abstract static class ScopesShortcut<T extends ActivityContext> extends SystemShortcut<T> {

protected String targetPackage;

private ScopesShortcut(int icon, int label, T target, ItemInfo itemInfo, View originalView) {
super(icon, label, target, itemInfo, originalView);
targetPackage = itemInfo.getTargetPackage();
}

protected static boolean hasGosPackageStateFlag(ItemInfo itemInfo, int flag) {
String pkg = itemInfo.getTargetPackage();
if (pkg == null) {
return false;
}
return GosPackageState.get(pkg, itemInfo.user).hasFlag(flag);
}

@Override
public void onClick(View v) {
dismissTaskMenuView();

Intent intent = getIntent(targetPackage);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
var opts = android.app.ActivityOptions.makeBasic()
.setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR)
.toBundle();
v.getContext().startActivityAsUser(intent, opts, mItemInfo.user);
}

protected abstract Intent getIntent(String targetPkg);
}

public static final Factory<BaseActivity> STORAGE_SCOPES = StorageScopes::maybeGet;

public static class StorageScopes<T extends ActivityContext> extends ScopesShortcut<T> {

private StorageScopes(T target, ItemInfo itemInfo, View originalView) {
super(R.drawable.ic_sscopes_add_file, R.string.storage_scopes_drop_target_label, target,
itemInfo, originalView);
}

@Nullable
public static <T extends ActivityContext> StorageScopes<T> maybeGet(T target, ItemInfo itemInfo, View originalView) {
if (hasGosPackageStateFlag(itemInfo, GosPackageStateFlag.STORAGE_SCOPES_ENABLED)) {
return new StorageScopes<>(target, itemInfo, originalView);
}

return null;
}

@Override
protected Intent getIntent(String targetPkg) {
return android.app.StorageScope.createConfigActivityIntent(targetPkg);
}
}

public static final Factory<BaseActivity> CONTACT_SCOPES = ContactScopes::maybeGet;

public static class ContactScopes<T extends ActivityContext> extends ScopesShortcut<T> {

private ContactScopes(T target, ItemInfo itemInfo, View originalView) {
super(R.drawable.ic_cscopes, R.string.contact_scopes_label, target,
itemInfo, originalView);
}

@Nullable
public static <T extends ActivityContext> ContactScopes<T> maybeGet(T target, ItemInfo itemInfo, View originalView) {
if (hasGosPackageStateFlag(itemInfo, GosPackageStateFlag.CONTACT_SCOPES_ENABLED)) {
return new ContactScopes<>(target, itemInfo, originalView);
}

return null;
}

@Override
protected Intent getIntent(String targetPkg) {
return android.ext.cscopes.ContactScopesApi.createConfigActivityIntent(targetPackage);
}
}

public static final Factory<ActivityContext> REMOVE = RemoveApp::new;

public static class RemoveApp<T extends ActivityContext> extends SystemShortcut<T> {
Expand Down