diff --git a/packages/CompanionDeviceManager/res/drawable/ic_apps.xml b/packages/CompanionDeviceManager/res/drawable/ic_apps.xml
new file mode 100644
index 0000000000000..f839b80d2e0c5
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/drawable/ic_apps.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/drawable/ic_notifications.xml b/packages/CompanionDeviceManager/res/drawable/ic_notifications.xml
new file mode 100644
index 0000000000000..4ac4d04b184e7
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/drawable/ic_notifications.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/drawable/ic_storage.xml b/packages/CompanionDeviceManager/res/drawable/ic_storage.xml
new file mode 100644
index 0000000000000..d8b7f59185c85
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/drawable/ic_storage.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml b/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
index f30dadffa7884..82fe72bee4e49 100644
--- a/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
+++ b/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
@@ -51,6 +51,11 @@
android:scrollbars="vertical"
android:layout_height="200dp" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/values/strings.xml b/packages/CompanionDeviceManager/res/values/strings.xml
index 9626751679e15..c4ad432b092ee 100644
--- a/packages/CompanionDeviceManager/res/values/strings.xml
+++ b/packages/CompanionDeviceManager/res/values/strings.xml
@@ -38,6 +38,12 @@
+
+ Apps
+
+
+ Stream your phone\u2019s apps
+
Allow <strong>%1$s</strong> to access this information for your phone
@@ -72,6 +78,18 @@
+
+ Notifications
+
+
+ Can read all notifications, including information like contracts, messages, and photos
+
+
+ Photos and media
+
+
+
+
Google Play services
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index 0fba250b200ad..1b626911fdde0 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -24,6 +24,9 @@ import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTE
import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService.DiscoveryState;
import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService.DiscoveryState.FINISHED_TIMEOUT;
+import static com.android.companiondevicemanager.PermissionListAdapter.TYPE_APPS;
+import static com.android.companiondevicemanager.PermissionListAdapter.TYPE_NOTIFICATION;
+import static com.android.companiondevicemanager.PermissionListAdapter.TYPE_STORAGE;
import static com.android.companiondevicemanager.Utils.getApplicationLabel;
import static com.android.companiondevicemanager.Utils.getHtmlFromResources;
import static com.android.companiondevicemanager.Utils.getVendorHeaderIcon;
@@ -61,6 +64,7 @@ import androidx.fragment.app.FragmentManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -122,8 +126,12 @@ public class CompanionDeviceActivity extends FragmentActivity implements
// The recycler view is only shown for multiple-device regular association request, after
// at least one matching device is found.
- private @Nullable RecyclerView mRecyclerView;
- private @Nullable DeviceListAdapter mAdapter;
+ private @Nullable RecyclerView mDeviceListRecyclerView;
+ private @Nullable DeviceListAdapter mDeviceAdapter;
+
+ // The recycler view is only shown for selfManaged association request.
+ private @Nullable RecyclerView mPermissionListRecyclerView;
+ private @Nullable PermissionListAdapter mPermissionListAdapter;
// The flag used to prevent double taps, that may lead to sending several requests for creating
// an association to CDM.
@@ -133,6 +141,8 @@ public class CompanionDeviceActivity extends FragmentActivity implements
// onActivityResult() after the association is created.
private @Nullable DeviceFilterPair> mSelectedDevice;
+ private @Nullable List mPermissionTypes;
+
@Override
public void onCreate(Bundle savedInstanceState) {
if (DEBUG) Log.d(TAG, "onCreate()");
@@ -242,8 +252,11 @@ public class CompanionDeviceActivity extends FragmentActivity implements
mVendorHeaderName = findViewById(R.id.vendor_header_name);
mVendorHeaderButton = findViewById(R.id.vendor_header_button);
- mRecyclerView = findViewById(R.id.device_list);
- mAdapter = new DeviceListAdapter(this, this::onListItemClick);
+ mDeviceListRecyclerView = findViewById(R.id.device_list);
+ mDeviceAdapter = new DeviceListAdapter(this, this::onListItemClick);
+
+ mPermissionListRecyclerView = findViewById(R.id.permission_list);
+ mPermissionListAdapter = new PermissionListAdapter(this);
mButtonAllow = findViewById(R.id.btn_positive);
mButtonNotAllow = findViewById(R.id.btn_negative);
@@ -359,7 +372,8 @@ public class CompanionDeviceActivity extends FragmentActivity implements
final Drawable vendorIcon;
final CharSequence vendorName;
final Spanned title;
- final Spanned summary;
+
+ mPermissionTypes = new ArrayList<>();
try {
vendorIcon = getVendorHeaderIcon(this, packageName, userId);
@@ -372,33 +386,36 @@ public class CompanionDeviceActivity extends FragmentActivity implements
switch (deviceProfile) {
case DEVICE_PROFILE_APP_STREAMING:
- title = getHtmlFromResources(this, R.string.title_app_streaming, appLabel);
- summary = getHtmlFromResources(
- this, R.string.summary_app_streaming, appLabel, deviceName);
+ title = getHtmlFromResources(this, R.string.title_app_streaming, deviceName);
+ mPermissionTypes.add(TYPE_APPS);
break;
case DEVICE_PROFILE_AUTOMOTIVE_PROJECTION:
- title = getHtmlFromResources(this, R.string.title_automotive_projection, appLabel);
- summary = getHtmlFromResources(
- this, R.string.summary_automotive_projection, appLabel, deviceName);
+ title = getHtmlFromResources(
+ this, R.string.title_automotive_projection, deviceName);
break;
case DEVICE_PROFILE_COMPUTER:
- title = getHtmlFromResources(this, R.string.title_computer, appLabel);
- summary = getHtmlFromResources(
- this, R.string.summary_computer, appLabel, deviceName);
+ title = getHtmlFromResources(this, R.string.title_computer, deviceName);
+ mPermissionTypes.add(TYPE_NOTIFICATION);
+ mPermissionTypes.add(TYPE_STORAGE);
break;
default:
throw new RuntimeException("Unsupported profile " + deviceProfile);
}
+ mSummary.setVisibility(View.GONE);
+
+ mPermissionListAdapter.setPermissionType(mPermissionTypes);
+ mPermissionListRecyclerView.setAdapter(mPermissionListAdapter);
+ mPermissionListRecyclerView.setLayoutManager(new LinearLayoutManager(this));
+
mTitle.setText(title);
- mSummary.setText(summary);
mVendorHeaderImage.setImageDrawable(vendorIcon);
mVendorHeaderName.setText(vendorName);
- mRecyclerView.setVisibility(View.GONE);
+ mDeviceListRecyclerView.setVisibility(View.GONE);
mVendorHeader.setVisibility(View.VISIBLE);
}
@@ -411,7 +428,8 @@ public class CompanionDeviceActivity extends FragmentActivity implements
deviceFilterPairs -> updateSingleDeviceUi(
deviceFilterPairs, deviceProfile, appLabel));
- mRecyclerView.setVisibility(View.GONE);
+ mPermissionListRecyclerView.setVisibility(View.GONE);
+ mDeviceListRecyclerView.setVisibility(View.GONE);
}
private void updateSingleDeviceUi(List> deviceFilterPairs,
@@ -460,15 +478,15 @@ public class CompanionDeviceActivity extends FragmentActivity implements
mTitle.setText(title);
mSummary.setText(summary);
- mAdapter = new DeviceListAdapter(this, this::onListItemClick);
+ mDeviceAdapter = new DeviceListAdapter(this, this::onListItemClick);
// TODO: hide the list and show a spinner until a first device matching device is found.
- mRecyclerView.setAdapter(mAdapter);
- mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
+ mDeviceListRecyclerView.setAdapter(mDeviceAdapter);
+ mDeviceListRecyclerView.setLayoutManager(new LinearLayoutManager(this));
CompanionDeviceDiscoveryService.getScanResult().observe(
/* lifecycleOwner */ this,
- /* observer */ mAdapter);
+ /* observer */ mDeviceAdapter);
// "Remove" consent button: users would need to click on the list item.
mButtonAllow.setVisibility(View.GONE);
@@ -477,14 +495,14 @@ public class CompanionDeviceActivity extends FragmentActivity implements
private void onListItemClick(int position) {
if (DEBUG) Log.d(TAG, "onListItemClick() " + position);
- final DeviceFilterPair> selectedDevice = mAdapter.getItem(position);
+ final DeviceFilterPair> selectedDevice = mDeviceAdapter.getItem(position);
if (mSelectedDevice != null) {
if (DEBUG) Log.w(TAG, "Already selected.");
return;
}
// Notify the adapter to highlight the selected item.
- mAdapter.setSelectedPosition(position);
+ mDeviceAdapter.setSelectedPosition(position);
mSelectedDevice = requireNonNull(selectedDevice);
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java
index e5513b0748651..8babd3ade1eb5 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java
@@ -15,9 +15,10 @@
*/
package com.android.companiondevicemanager;
+
+import static com.android.companiondevicemanager.Utils.getIcon;
+
import android.content.Context;
-import android.graphics.Color;
-import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -60,11 +61,11 @@ class DeviceListAdapter extends RecyclerView.Adapter {
+ private final Context mContext;
+
+ private List mPermissions;
+
+ static final int TYPE_NOTIFICATION = 0;
+ static final int TYPE_STORAGE = 1;
+ static final int TYPE_APPS = 2;
+
+ private static final Map sTitleMap;
+ static {
+ final Map map = new ArrayMap<>();
+ map.put(TYPE_NOTIFICATION, R.string.permission_notification);
+ map.put(TYPE_STORAGE, R.string.permission_storage);
+ map.put(TYPE_APPS, R.string.permission_apps);
+ sTitleMap = unmodifiableMap(map);
+ }
+
+ private static final Map sSummaryMap;
+ static {
+ final Map map = new ArrayMap<>();
+ map.put(TYPE_NOTIFICATION, R.string.permission_notification_summary);
+ map.put(TYPE_STORAGE, R.string.permission_storage_summary);
+ map.put(TYPE_APPS, R.string.permission_apps_summary);
+ sSummaryMap = unmodifiableMap(map);
+ }
+
+ private static final Map sIconMap;
+ static {
+ final Map map = new ArrayMap<>();
+ map.put(TYPE_NOTIFICATION, R.drawable.ic_notifications);
+ map.put(TYPE_STORAGE, R.drawable.ic_storage);
+ map.put(TYPE_APPS, R.drawable.ic_apps);
+ sIconMap = unmodifiableMap(map);
+ }
+
+ PermissionListAdapter(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(parent.getContext()).inflate(
+ R.layout.list_item_permission, parent, false);
+ ViewHolder viewHolder = new ViewHolder(view);
+ viewHolder.mPermissionIcon.setImageDrawable(getIcon(mContext, sIconMap.get(viewType)));
+
+ return viewHolder;
+ }
+
+ @Override
+ public void onBindViewHolder(ViewHolder holder, int position) {
+ int type = getItemViewType(position);
+ final Spanned title = getHtmlFromResources(mContext, sTitleMap.get(type));
+ final Spanned summary = getHtmlFromResources(mContext, sSummaryMap.get(type));
+
+ holder.mPermissionName.setText(title);
+ holder.mPermissionSummary.setText(summary);
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ return mPermissions.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public int getItemCount() {
+ return mPermissions != null ? mPermissions.size() : 0;
+ }
+
+ static class ViewHolder extends RecyclerView.ViewHolder {
+ private final TextView mPermissionName;
+ private final TextView mPermissionSummary;
+ private final ImageView mPermissionIcon;
+ ViewHolder(View itemView) {
+ super(itemView);
+ mPermissionName = itemView.findViewById(R.id.permission_name);
+ mPermissionSummary = itemView.findViewById(R.id.permission_summary);
+ mPermissionIcon = itemView.findViewById(R.id.permission_icon);
+ }
+ }
+
+ void setPermissionType(List permissions) {
+ mPermissions = permissions;
+ }
+}
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java
index 76bbcfb791557..d5b2f0a748f1b 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java
@@ -22,6 +22,7 @@ import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.ApplicationInfoFlags;
+import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
@@ -121,6 +122,12 @@ class Utils {
return appInfo;
}
+ static @NonNull Drawable getIcon(@NonNull Context context, int resId) {
+ Drawable icon = context.getResources().getDrawable(resId, null);
+ icon.setTint(Color.DKGRAY);
+ return icon;
+ }
+
static void runOnMainThread(Runnable runnable) {
if (Thread.currentThread() == Looper.getMainLooper().getThread()) {
runnable.run();