summaryrefslogtreecommitdiff
path: root/go
diff options
context:
space:
mode:
authorJon Spivack <spivack@google.com>2021-08-13 13:18:24 -0700
committerJon Spivack <spivack@google.com>2021-09-20 17:11:04 -0700
commit89c21c77f538bb32640c56fa045190bfba053d08 (patch)
tree1dcdfb4e0319eb7fa1521faa0f6b186a54e62357 /go
parent0b6246f5a00e3c550794e0198ee46190e10cdfd2 (diff)
downloadLauncher3-89c21c77f538bb32640c56fa045190bfba053d08.tar.gz
P2P App Sharing: Add Shareability Cache
This update allows Launcher to check with an external API to determine whether apps are shareable before displaying the Share App button. To prevent extraneous calls to the API, the retrieved shareability data are cached. A job is scheduled to update this cache once a week. This feature can be toggled with the ENABLE_SHAREABILITY_CHECK flag in AppSharing.java. It is currently disabled, as the Play API has only been partially rolled out. More details on the design are available at go/app-shareability-cache-design Bug: 168831749 Test: manual (local Wembley device) Test: m -j RunLauncherGoGoogleRoboTests ROBOTEST_FILTER="AppShareabilityManagerTest|AppSharingTest" Change-Id: I971a3776e09b6842dedf315ec592317050dd6790
Diffstat (limited to 'go')
-rw-r--r--go/AndroidManifest.xml4
-rw-r--r--go/quickstep/res/values/integers.xml20
-rw-r--r--go/quickstep/src/com/android/launcher3/AppSharing.java67
-rw-r--r--go/quickstep/src/com/android/launcher3/model/AppShareabilityChecker.java38
-rw-r--r--go/quickstep/src/com/android/launcher3/model/AppShareabilityDatabase.java60
-rw-r--r--go/quickstep/src/com/android/launcher3/model/AppShareabilityJobService.java77
-rw-r--r--go/quickstep/src/com/android/launcher3/model/AppShareabilityManager.java211
-rw-r--r--go/quickstep/src/com/android/launcher3/model/AppShareabilityStatus.java39
8 files changed, 503 insertions, 13 deletions
diff --git a/go/AndroidManifest.xml b/go/AndroidManifest.xml
index 2671604f94..728b3262f0 100644
--- a/go/AndroidManifest.xml
+++ b/go/AndroidManifest.xml
@@ -54,6 +54,10 @@
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"
android:enabled="false"
tools:node="replace" />
+
+ <service
+ android:name="com.android.launcher3.model.AppShareabilityJobService"
+ android:permission="android.permission.BIND_JOB_SERVICE" />
</application>
</manifest>
diff --git a/go/quickstep/res/values/integers.xml b/go/quickstep/res/values/integers.xml
new file mode 100644
index 0000000000..e6e8111eab
--- /dev/null
+++ b/go/quickstep/res/values/integers.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 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.
+ -->
+<resources>
+ <!-- Job IDs must be integers unique within their package -->
+ <integer name="app_shareability_job_id">200</integer>
+</resources> \ No newline at end of file
diff --git a/go/quickstep/src/com/android/launcher3/AppSharing.java b/go/quickstep/src/com/android/launcher3/AppSharing.java
index b72e71c2b5..fd5456c73b 100644
--- a/go/quickstep/src/com/android/launcher3/AppSharing.java
+++ b/go/quickstep/src/com/android/launcher3/AppSharing.java
@@ -28,7 +28,12 @@ import android.view.View;
import androidx.core.content.FileProvider;
+import com.android.launcher3.model.AppShareabilityChecker;
+import com.android.launcher3.model.AppShareabilityJobService;
+import com.android.launcher3.model.AppShareabilityManager;
+import com.android.launcher3.model.AppShareabilityManager.ShareabilityStatus;
import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.popup.PopupDataProvider;
import com.android.launcher3.popup.SystemShortcut;
import java.io.File;
@@ -44,6 +49,11 @@ public final class AppSharing {
* because it is unique to Go and not toggleable at runtime.
*/
public static final boolean ENABLE_APP_SHARING = true;
+ /**
+ * With this flag enabled, the Share App button will be dynamically enabled/disabled based
+ * on each app's shareability status.
+ */
+ public static final boolean ENABLE_SHAREABILITY_CHECK = false;
private static final String TAG = "AppSharing";
private static final String FILE_PROVIDER_SUFFIX = ".overview.fileprovider";
@@ -51,22 +61,12 @@ public final class AppSharing {
private static final String APP_MIME_TYPE = "application/application";
private final String mSharingComponent;
+ private AppShareabilityManager mShareabilityMgr;
private AppSharing(Launcher launcher) {
mSharingComponent = launcher.getText(R.string.app_sharing_component).toString();
}
- private boolean canShare(ItemInfo info) {
- /**
- * TODO: Implement once b/168831749 has been resolved
- * The implementation should check the validity of the app.
- * It should also check whether the app is free or paid, returning false in the latter case.
- * For now, all checks occur in the sharing app.
- * So, we simply check whether the sharing app is defined.
- */
- return !TextUtils.isEmpty(mSharingComponent);
- }
-
private Uri getShareableUri(Context context, String path, String displayName) {
String authority = BuildConfig.APPLICATION_ID + FILE_PROVIDER_SUFFIX;
File pathFile = new File(path);
@@ -74,19 +74,39 @@ public final class AppSharing {
}
private SystemShortcut<Launcher> getShortcut(Launcher launcher, ItemInfo info) {
- if (!canShare(info)) {
+ if (TextUtils.isEmpty(mSharingComponent)) {
return null;
}
-
return new Share(launcher, info);
}
/**
+ * Instantiates AppShareabilityManager, which then reads app shareability data from disk
+ * Also schedules a job to update those data
+ * @param context The application context
+ * @param checker An implementation of AppShareabilityChecker to perform the actual checks
+ * when updating the data
+ */
+ public static void setUpShareabilityCache(Context context, AppShareabilityChecker checker) {
+ AppShareabilityManager shareMgr = AppShareabilityManager.INSTANCE.get(context);
+ shareMgr.setShareabilityChecker(checker);
+ AppShareabilityJobService.schedule(context);
+ }
+
+ /**
* The Share App system shortcut, used to initiate p2p sharing of a given app
*/
public final class Share extends SystemShortcut<Launcher> {
+ private PopupDataProvider mPopupDataProvider;
+
public Share(Launcher target, ItemInfo itemInfo) {
super(R.drawable.ic_share, R.string.app_share_drop_target_label, target, itemInfo);
+ mPopupDataProvider = target.getPopupDataProvider();
+
+ if (ENABLE_SHAREABILITY_CHECK) {
+ mShareabilityMgr = AppShareabilityManager.INSTANCE.get(target);
+ checkShareability(/* requestUpdateIfUnknown */ true);
+ }
}
@Override
@@ -122,6 +142,27 @@ public final class AppSharing {
AbstractFloatingView.closeAllOpenViews(mTarget);
}
+
+ private void onStatusUpdated(boolean success) {
+ if (!success) {
+ // Something went wrong. Specific error logged in AppShareabilityManager.
+ return;
+ }
+ checkShareability(/* requestUpdateIfUnknown */ false);
+ mTarget.runOnUiThread(() -> {
+ mPopupDataProvider.redrawSystemShortcuts();
+ });
+ }
+
+ private void checkShareability(boolean requestUpdateIfUnknown) {
+ String packageName = mItemInfo.getTargetComponent().getPackageName();
+ @ShareabilityStatus int status = mShareabilityMgr.getStatus(packageName);
+ setEnabled(status == ShareabilityStatus.SHAREABLE);
+
+ if (requestUpdateIfUnknown && status == ShareabilityStatus.UNKNOWN) {
+ mShareabilityMgr.requestAppStatusUpdate(packageName, this::onStatusUpdated);
+ }
+ }
}
/**
diff --git a/go/quickstep/src/com/android/launcher3/model/AppShareabilityChecker.java b/go/quickstep/src/com/android/launcher3/model/AppShareabilityChecker.java
new file mode 100644
index 0000000000..0a82904670
--- /dev/null
+++ b/go/quickstep/src/com/android/launcher3/model/AppShareabilityChecker.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 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.model;
+
+import androidx.annotation.Nullable;
+
+import java.util.List;
+import java.util.function.Consumer;
+
+/**
+ * Interface for checking apps' shareability. Implementations need to be able to determine whether
+ * apps are shareable given their package names.
+ */
+public interface AppShareabilityChecker {
+ /**
+ * Checks the shareability of the provided apps. Once the check is complete, updates the
+ * provided manager with the results and calls the (optionally) provided callback.
+ * @param packageNames The apps to check
+ * @param shareMgr The manager to receive the results
+ * @param callback Optional callback to be invoked when the check is finished
+ */
+ void checkApps(List<String> packageNames, AppShareabilityManager shareMgr,
+ @Nullable Consumer<Boolean> callback);
+}
diff --git a/go/quickstep/src/com/android/launcher3/model/AppShareabilityDatabase.java b/go/quickstep/src/com/android/launcher3/model/AppShareabilityDatabase.java
new file mode 100644
index 0000000000..03eed7eccc
--- /dev/null
+++ b/go/quickstep/src/com/android/launcher3/model/AppShareabilityDatabase.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2021 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.model;
+
+import androidx.room.Dao;
+import androidx.room.Database;
+import androidx.room.Insert;
+import androidx.room.OnConflictStrategy;
+import androidx.room.Query;
+import androidx.room.RoomDatabase;
+import androidx.room.Update;
+
+import java.util.List;
+
+/**
+ * This database maintains a collection of AppShareabilityStatus items
+ * In its intended use case, there will be one entry for each app installed on the device
+ */
+@Database(entities = {AppShareabilityStatus.class}, exportSchema = false, version = 1)
+public abstract class AppShareabilityDatabase extends RoomDatabase {
+ /**
+ * Data Access Object for this database
+ */
+ @Dao
+ public interface ShareabilityDao {
+ /** Add an AppShareabilityStatus to the database */
+ @Insert(onConflict = OnConflictStrategy.REPLACE)
+ void insertAppStatus(AppShareabilityStatus status);
+
+ /** Add a collection of AppShareabilityStatus objects to the database */
+ @Insert(onConflict = OnConflictStrategy.REPLACE)
+ void insertAppStatuses(AppShareabilityStatus... statuses);
+
+ /**
+ * Update an AppShareabilityStatus in the database
+ * @return The number of entries successfully updated
+ */
+ @Update
+ int updateAppStatus(AppShareabilityStatus status);
+
+ /** Retrieve all entries from the database */
+ @Query("SELECT * FROM AppShareabilityStatus")
+ List<AppShareabilityStatus> getAllEntries();
+ }
+
+ protected abstract ShareabilityDao shareabilityDao();
+}
diff --git a/go/quickstep/src/com/android/launcher3/model/AppShareabilityJobService.java b/go/quickstep/src/com/android/launcher3/model/AppShareabilityJobService.java
new file mode 100644
index 0000000000..60bea53c70
--- /dev/null
+++ b/go/quickstep/src/com/android/launcher3/model/AppShareabilityJobService.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2021 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.model;
+
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.content.ComponentName;
+import android.content.Context;
+import android.util.Log;
+
+import com.android.launcher3.R;
+
+/**
+ * A job to request AppShareabilityManager to update its shareability data
+ * The shareability status of an app is not expected to change often, so this job is only
+ * run periodically.
+ */
+public final class AppShareabilityJobService extends JobService {
+
+ private static final String TAG = "AppShareabilityJobService";
+ // Run this job once a week
+ private static final int RECURRENCE_INTERVAL_MILLIS = 604800000;
+
+ @Override
+ public boolean onStartJob(final JobParameters params) {
+ Context context = getApplicationContext();
+ AppShareabilityManager.INSTANCE.get(context).requestFullUpdate();
+ return false; // Job is finished
+ }
+
+ @Override
+ public boolean onStopJob(final JobParameters params) {
+ Log.d(TAG, "App shareability data update job stopped; id=" + params.getJobId()
+ + ", reason="
+ + JobParameters.getInternalReasonCodeDescription(params.getStopReason()));
+ return true; // Reschedule the job
+ }
+
+ /**
+ * Creates and schedules the job.
+ * Does not schedule a duplicate job if one is already pending.
+ * @param context The application context
+ */
+ public static void schedule(Context context) {
+ final JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
+
+ final JobInfo pendingJob = jobScheduler.getPendingJob(R.integer.app_shareability_job_id);
+ if (pendingJob != null) {
+ // Don't schedule duplicate jobs
+ return;
+ }
+
+ final JobInfo newJob = new JobInfo.Builder(R.integer.app_shareability_job_id,
+ new ComponentName(context, AppShareabilityJobService.class))
+ .setPeriodic(RECURRENCE_INTERVAL_MILLIS)
+ .setPersisted(true)
+ .setRequiresBatteryNotLow(true)
+ .build();
+ jobScheduler.schedule(newJob);
+ }
+}
diff --git a/go/quickstep/src/com/android/launcher3/model/AppShareabilityManager.java b/go/quickstep/src/com/android/launcher3/model/AppShareabilityManager.java
new file mode 100644
index 0000000000..cf80c35972
--- /dev/null
+++ b/go/quickstep/src/com/android/launcher3/model/AppShareabilityManager.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2021 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.model;
+
+import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.content.Context;
+import android.content.pm.LauncherActivityInfo;
+import android.content.pm.LauncherApps;
+import android.os.Process;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.Nullable;
+import androidx.annotation.WorkerThread;
+import androidx.room.Room;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.launcher3.model.AppShareabilityDatabase.ShareabilityDao;
+import com.android.launcher3.util.MainThreadInitializedObject;
+
+import java.lang.annotation.Retention;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+
+/**
+ * This class maintains the shareability status of installed apps.
+ * Each app's status is retrieved from the Play Store's API. Statuses are cached in order
+ * to limit extraneous calls to that API (which can be time-consuming).
+ */
+public final class AppShareabilityManager {
+ @Retention(SOURCE)
+ @IntDef({
+ ShareabilityStatus.UNKNOWN,
+ ShareabilityStatus.NOT_SHAREABLE,
+ ShareabilityStatus.SHAREABLE
+ })
+ public @interface ShareabilityStatus {
+ int UNKNOWN = 0;
+ int NOT_SHAREABLE = 1;
+ int SHAREABLE = 2;
+ }
+
+ private static final String TAG = "AppShareabilityManager";
+ private static final String DB_NAME = "shareabilityDatabase";
+ public static MainThreadInitializedObject<AppShareabilityManager> INSTANCE =
+ new MainThreadInitializedObject<>(AppShareabilityManager::new);
+
+ private final Context mContext;
+ // Local map to store the data in memory for quick access
+ private final Map<String, Integer> mDataMap;
+ // Database to persist the data across reboots
+ private AppShareabilityDatabase mDatabase;
+ // Data Access Object for the database
+ private ShareabilityDao mDao;
+ // Class to perform shareability checks
+ private AppShareabilityChecker mShareChecker;
+
+ private AppShareabilityManager(Context context) {
+ mContext = context;
+ mDataMap = new ArrayMap<>();
+ mDatabase = Room.databaseBuilder(mContext, AppShareabilityDatabase.class, DB_NAME).build();
+ mDao = mDatabase.shareabilityDao();
+ MODEL_EXECUTOR.post(this::readFromDB);
+ }
+
+ /**
+ * Set the shareability checker. The checker determines whether given apps are shareable.
+ * This must be set before the manager can update its data.
+ * @param checker Implementation of AppShareabilityChecker to perform the checks
+ */
+ public void setShareabilityChecker(AppShareabilityChecker checker) {
+ mShareChecker = checker;
+ }
+
+ /**
+ * Retrieve the ShareabilityStatus of an app from the local map
+ * This does not interact with the saved database
+ * @param packageName The app's package name
+ * @return The status as a ShareabilityStatus integer
+ */
+ public synchronized @ShareabilityStatus int getStatus(String packageName) {
+ @ShareabilityStatus int status = ShareabilityStatus.UNKNOWN;
+ if (mDataMap.containsKey(packageName)) {
+ status = mDataMap.get(packageName);
+ }
+ return status;
+ }
+
+ /**
+ * Set the status of a given app. This updates the local map as well as the saved database.
+ */
+ public synchronized void setStatus(String packageName, @ShareabilityStatus int status) {
+ mDataMap.put(packageName, status);
+
+ // Write to the database on a separate thread
+ MODEL_EXECUTOR.post(() ->
+ mDao.insertAppStatus(new AppShareabilityStatus(packageName, status)));
+ }
+
+ /**
+ * Set the statuses of given apps. This updates the local map as well as the saved database.
+ */
+ public synchronized void setStatuses(List<AppShareabilityStatus> statuses) {
+ for (int i = 0, size = statuses.size(); i < size; i++) {
+ AppShareabilityStatus entry = statuses.get(i);
+ mDataMap.put(entry.packageName, entry.status);
+ }
+
+ // Write to the database on a separate thread
+ MODEL_EXECUTOR.post(() ->
+ mDao.insertAppStatuses(statuses.toArray(new AppShareabilityStatus[0])));
+ }
+
+ /**
+ * Request a status update for a specific app
+ * @param packageName The app's package name
+ * @param callback Optional callback to be called when the update is complete. The received
+ * Boolean denotes whether the update was successful.
+ */
+ public void requestAppStatusUpdate(String packageName, @Nullable Consumer<Boolean> callback) {
+ MODEL_EXECUTOR.post(() -> updateCache(packageName, callback));
+ }
+
+ /**
+ * Request a status update for all apps
+ */
+ public void requestFullUpdate() {
+ MODEL_EXECUTOR.post(this::updateCache);
+ }
+
+ /**
+ * Update the cached shareability data for all installed apps
+ */
+ @WorkerThread
+ private void updateCache() {
+ updateCache(/* packageName */ null, /* callback */ null);
+ }
+
+ /**
+ * Update the cached shareability data
+ * @param packageName A specific package to update. If null, all installed apps will be updated.
+ * @param callback Optional callback to be called when the update is complete. The received
+ * Boolean denotes whether the update was successful.
+ */
+ @WorkerThread
+ private void updateCache(@Nullable String packageName, @Nullable Consumer<Boolean> callback) {
+ if (mShareChecker == null) {
+ Log.e(TAG, "AppShareabilityChecker not set");
+ return;
+ }
+
+ List<String> packageNames = new ArrayList<>();
+ if (packageName != null) {
+ packageNames.add(packageName);
+ } else {
+ LauncherApps launcherApps = mContext.getSystemService(LauncherApps.class);
+ List<LauncherActivityInfo> installedApps =
+ launcherApps.getActivityList(/* packageName */ null, Process.myUserHandle());
+ for (int i = 0, size = installedApps.size(); i < size; i++) {
+ packageNames.add(installedApps.get(i).getApplicationInfo().packageName);
+ }
+ }
+
+ mShareChecker.checkApps(packageNames, this, callback);
+ }
+
+ @WorkerThread
+ private synchronized void readFromDB() {
+ mDataMap.clear();
+ List<AppShareabilityStatus> entries = mDao.getAllEntries();
+ for (int i = 0, size = entries.size(); i < size; i++) {
+ AppShareabilityStatus entry = entries.get(i);
+ mDataMap.put(entry.packageName, entry.status);
+ }
+ }
+
+ /**
+ * Provides a testable instance of this class
+ * This instance allows database queries on the main thread
+ * @hide */
+ @VisibleForTesting
+ public static AppShareabilityManager getTestInstance(Context context) {
+ AppShareabilityManager manager = new AppShareabilityManager(context);
+ manager.mDatabase.close();
+ manager.mDatabase = Room.inMemoryDatabaseBuilder(context, AppShareabilityDatabase.class)
+ .allowMainThreadQueries()
+ .build();
+ manager.mDao = manager.mDatabase.shareabilityDao();
+ return manager;
+ }
+}
diff --git a/go/quickstep/src/com/android/launcher3/model/AppShareabilityStatus.java b/go/quickstep/src/com/android/launcher3/model/AppShareabilityStatus.java
new file mode 100644
index 0000000000..61018c6b25
--- /dev/null
+++ b/go/quickstep/src/com/android/launcher3/model/AppShareabilityStatus.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 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.model;
+
+import androidx.annotation.NonNull;
+import androidx.room.Entity;
+import androidx.room.PrimaryKey;
+
+import com.android.launcher3.model.AppShareabilityManager.ShareabilityStatus;
+
+/**
+ * Database entry to hold the shareability status of a single app
+ */
+@Entity
+public class AppShareabilityStatus {
+ @PrimaryKey
+ @NonNull
+ public String packageName;
+
+ public @ShareabilityStatus int status;
+
+ public AppShareabilityStatus(@NonNull String packageName, @ShareabilityStatus int status) {
+ this.packageName = packageName;
+ this.status = status;
+ }
+}