Add CDM profile for "glasses"
* add profile and normal permission to use the profile
* add profile and the permission to the map of valid roles on the
service side
* update the CompanionDeviceActivity to handle the glasses device
profile, for both single and multiple device cases
* add relevant strings for the glasses profile and icon
* add "glasses" profile to MetricUtils
Bug: 256140614
Test: atest CtsCompanionDeviceManagerCoreTestCases
Test: atest CtsCompanionDeviceManagerNoCompanionServicesTestCases
Test: atest CtsCompanionDeviceManagerUiAutomationTestCases
Change-Id: I30213a1ee8e5122ff99b1feb94e3c847de57a6fd
Signed-off-by: Claudiu Ghioc <[email protected]>
diff --git a/core/api/current.txt b/core/api/current.txt
index cefc856..828d4b9 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -176,6 +176,7 @@
field public static final String REQUEST_COMPANION_PROFILE_APP_STREAMING = "android.permission.REQUEST_COMPANION_PROFILE_APP_STREAMING";
field public static final String REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION = "android.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION";
field public static final String REQUEST_COMPANION_PROFILE_COMPUTER = "android.permission.REQUEST_COMPANION_PROFILE_COMPUTER";
+ field public static final String REQUEST_COMPANION_PROFILE_GLASSES = "android.permission.REQUEST_COMPANION_PROFILE_GLASSES";
field public static final String REQUEST_COMPANION_PROFILE_WATCH = "android.permission.REQUEST_COMPANION_PROFILE_WATCH";
field public static final String REQUEST_COMPANION_RUN_IN_BACKGROUND = "android.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND";
field public static final String REQUEST_COMPANION_SELF_MANAGED = "android.permission.REQUEST_COMPANION_SELF_MANAGED";
@@ -9052,6 +9053,7 @@
field @RequiresPermission(android.Manifest.permission.REQUEST_COMPANION_PROFILE_APP_STREAMING) public static final String DEVICE_PROFILE_APP_STREAMING = "android.app.role.COMPANION_DEVICE_APP_STREAMING";
field @RequiresPermission(android.Manifest.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION) public static final String DEVICE_PROFILE_AUTOMOTIVE_PROJECTION = "android.app.role.SYSTEM_AUTOMOTIVE_PROJECTION";
field @RequiresPermission(android.Manifest.permission.REQUEST_COMPANION_PROFILE_COMPUTER) public static final String DEVICE_PROFILE_COMPUTER = "android.app.role.COMPANION_DEVICE_COMPUTER";
+ field @RequiresPermission(android.Manifest.permission.REQUEST_COMPANION_PROFILE_GLASSES) public static final String DEVICE_PROFILE_GLASSES = "android.app.role.COMPANION_DEVICE_GLASSES";
field public static final String DEVICE_PROFILE_WATCH = "android.app.role.COMPANION_DEVICE_WATCH";
}
diff --git a/core/java/android/companion/AssociationRequest.java b/core/java/android/companion/AssociationRequest.java
index 3325d1e..57517f1 100644
--- a/core/java/android/companion/AssociationRequest.java
+++ b/core/java/android/companion/AssociationRequest.java
@@ -73,6 +73,21 @@
public static final String DEVICE_PROFILE_WATCH = "android.app.role.COMPANION_DEVICE_WATCH";
/**
+ * Device profile: glasses.
+ *
+ * If specified, the current request may have a modified UI to highlight that the device being
+ * set up is a glasses device, and some extra permissions may be granted to the app
+ * as a result.
+ *
+ * Using it requires declaring uses-permission
+ * {@link android.Manifest.permission#REQUEST_COMPANION_PROFILE_GLASSES} in the manifest.
+ *
+ * @see AssociationRequest.Builder#setDeviceProfile
+ */
+ @RequiresPermission(Manifest.permission.REQUEST_COMPANION_PROFILE_GLASSES)
+ public static final String DEVICE_PROFILE_GLASSES = "android.app.role.COMPANION_DEVICE_GLASSES";
+
+ /**
* Device profile: a virtual display capable of rendering Android applications, and sending back
* input events.
*
@@ -116,7 +131,8 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@StringDef(value = { DEVICE_PROFILE_WATCH, DEVICE_PROFILE_COMPUTER,
- DEVICE_PROFILE_AUTOMOTIVE_PROJECTION, DEVICE_PROFILE_APP_STREAMING })
+ DEVICE_PROFILE_AUTOMOTIVE_PROJECTION, DEVICE_PROFILE_APP_STREAMING,
+ DEVICE_PROFILE_GLASSES })
public @interface DeviceProfile {}
/**
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index dc24b0f9..5b634d9 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3349,6 +3349,14 @@
android:description="@string/permdesc_companionProfileWatch"
android:protectionLevel="normal" />
+ <!-- Allows app to request to be associated with a device via
+ {@link android.companion.CompanionDeviceManager}
+ as "glasses"
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.REQUEST_COMPANION_PROFILE_GLASSES"
+ android:protectionLevel="normal" />
+
<!-- Allows application to request to be associated with a virtual display capable of streaming
Android applications
({@link android.companion.AssociationRequest#DEVICE_PROFILE_APP_STREAMING})
diff --git a/packages/CompanionDeviceManager/res/drawable/ic_glasses.xml b/packages/CompanionDeviceManager/res/drawable/ic_glasses.xml
new file mode 100644
index 0000000..5f8d566
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/drawable/ic_glasses.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24dp"
+ android:width="24dp"
+ android:viewportHeight="160"
+ android:viewportWidth="160" >
+ <path android:fillAlpha="0" android:fillColor="#000000"
+ android:pathData="M69.48,83.33A26.97,24.46 0,0 1,42.92 107.8,26.97 24.46,0 0,1 15.56,84.07 26.97,24.46 0,0 1,41.29 58.9,26.97 24.46,0 0,1 69.43,81.86"
+ android:strokeColor="#000000" android:strokeWidth="2.265"/>
+ <path android:fillAlpha="0" android:fillColor="#000000"
+ android:pathData="m143.73,83.58a26.97,24.46 0,0 1,-26.56 24.46,26.97 24.46,0 0,1 -27.36,-23.72 26.97,24.46 0,0 1,25.73 -25.18,26.97 24.46,0 0,1 28.14,22.96"
+ android:strokeColor="#000000" android:strokeWidth="2.265"/>
+ <path android:fillAlpha="0" android:fillColor="#000000"
+ android:pathData="m69.42,82.98c20.37,-0.25 20.37,-0.25 20.37,-0.25"
+ android:strokeColor="#000000" android:strokeWidth="2.265"/>
+ <path android:fillAlpha="0" android:fillColor="#000000"
+ android:pathData="M15.37,83.78 L1.9,56.83"
+ android:strokeColor="#000000" android:strokeWidth="2.265"/>
+ <path android:fillAlpha="0" android:fillColor="#000000"
+ android:pathData="M143.67,82.75C154.48,57.9 154.48,58.04 154.48,58.04"
+ android:strokeColor="#000000" android:strokeWidth="2.265"/>
+</vector>
diff --git a/packages/CompanionDeviceManager/res/values/strings.xml b/packages/CompanionDeviceManager/res/values/strings.xml
index 97201e2..a5daeb2 100644
--- a/packages/CompanionDeviceManager/res/values/strings.xml
+++ b/packages/CompanionDeviceManager/res/values/strings.xml
@@ -36,6 +36,18 @@
<!-- Description of the privileges the application will get if associated with the companion device of WATCH profile for singleDevice(type) [CHAR LIMIT=NONE] -->
<string name="summary_watch_single_device">The app is needed to manage your <xliff:g id="device_name" example="My Watch">%1$s</xliff:g>. <xliff:g id="app_name" example="Android Wear">%2$s</xliff:g> will be allowed to interact with these permissions:</string>
+ <!-- TODO(b/256140614) To replace all glasses related strings with final versions -->
+ <!-- ================= DEVICE_PROFILE_GLASSES ================= -->
+
+ <!-- The name of the "glasses" device type [CHAR LIMIT=30] -->
+ <string name="profile_name_glasses">glasses</string>
+
+ <!-- Description of the privileges the application will get if associated with the companion device of GLASSES profile (type) [CHAR LIMIT=NONE] -->
+ <string name="summary_glasses">This app is needed to manage your <xliff:g id="device_name" example="My Glasses">%1$s</xliff:g>. <xliff:g id="app_name" example="Glasses">%2$s</xliff:g> will be allowed to access your Phone, SMS, Contacts, Microphone and Nearby devices permissions.</string>
+
+ <!-- Description of the privileges the application will get if associated with the companion device of GLASSES profile for singleDevice(type) [CHAR LIMIT=NONE] -->
+ <string name="summary_glasses_single_device">The app is needed to manage your <xliff:g id="device_name" example="My Glasses">%1$s</xliff:g>. <xliff:g id="app_name" example="Glasses">%2$s</xliff:g> will be allowed to interact with these permissions:</string>
+
<!-- ================= DEVICE_PROFILE_APP_STREAMING ================= -->
<!-- Confirmation for associating an application with a companion device of APP_STREAMING profile (type) [CHAR LIMIT=NONE] -->
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index 3a3a5d2..c95b3bc 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -19,6 +19,7 @@
import static android.companion.AssociationRequest.DEVICE_PROFILE_APP_STREAMING;
import static android.companion.AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION;
import static android.companion.AssociationRequest.DEVICE_PROFILE_COMPUTER;
+import static android.companion.AssociationRequest.DEVICE_PROFILE_GLASSES;
import static android.companion.AssociationRequest.DEVICE_PROFILE_WATCH;
import static android.companion.CompanionDeviceManager.REASON_CANCELED;
import static android.companion.CompanionDeviceManager.REASON_DISCOVERY_TIMEOUT;
@@ -556,7 +557,7 @@
}
final String deviceName = mSelectedDevice.getDisplayName();
- final String profileName = getString(R.string.profile_name_watch);
+ final String profileName;
final Spanned title;
final Spanned summary;
final Drawable profileIcon;
@@ -569,6 +570,7 @@
mSummary.setVisibility(View.GONE);
mConstraintList.setVisibility(View.GONE);
} else if (deviceProfile.equals(DEVICE_PROFILE_WATCH)) {
+ profileName = getString(R.string.profile_name_watch);
title = getHtmlFromResources(this, R.string.confirmation_title, appLabel, deviceName);
summary = getHtmlFromResources(
this, R.string.summary_watch_single_device, profileName, appLabel);
@@ -579,6 +581,19 @@
PERMISSION_CALENDAR, PERMISSION_NEARBY_DEVICES));
setupPermissionList();
+ } else if (deviceProfile.equals(DEVICE_PROFILE_GLASSES)) {
+ profileName = getString(R.string.profile_name_glasses);
+ title = getHtmlFromResources(this, R.string.confirmation_title, appLabel, profileName);
+ summary = getHtmlFromResources(
+ this, R.string.summary_glasses_single_device, profileName, appLabel);
+ profileIcon = getIcon(this, R.drawable.ic_glasses);
+
+ // TODO (b/256140614): add PERMISSION_MICROPHONE
+ mPermissionTypes.addAll(Arrays.asList(
+ PERMISSION_PHONE, PERMISSION_SMS, PERMISSION_CONTACTS,
+ PERMISSION_NEARBY_DEVICES));
+
+ setupPermissionList();
} else {
throw new RuntimeException("Unsupported profile " + deviceProfile);
}
@@ -607,6 +622,10 @@
profileName = getString(R.string.profile_name_watch);
summary = getHtmlFromResources(this, R.string.summary_watch, profileName, appLabel);
profileIcon = getIcon(this, R.drawable.ic_watch);
+ } else if (deviceProfile.equals(DEVICE_PROFILE_GLASSES)) {
+ profileName = getString(R.string.profile_name_glasses);
+ summary = getHtmlFromResources(this, R.string.summary_glasses, profileName, appLabel);
+ profileIcon = getIcon(this, R.drawable.ic_glasses);
} else {
throw new RuntimeException("Unsupported profile " + deviceProfile);
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 973d0de..533ad18 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -322,6 +322,7 @@
<uses-permission android:name="android.permission.REQUEST_COMPANION_PROFILE_COMPUTER" />
<uses-permission android:name="android.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION" />
<uses-permission android:name="android.permission.REQUEST_COMPANION_PROFILE_WATCH" />
+ <uses-permission android:name="android.permission.REQUEST_COMPANION_PROFILE_GLASSES" />
<uses-permission android:name="android.permission.REQUEST_COMPANION_SELF_MANAGED" />
<uses-permission android:name="android.permission.MANAGE_APPOPS" />
diff --git a/services/companion/java/com/android/server/companion/MetricUtils.java b/services/companion/java/com/android/server/companion/MetricUtils.java
index 09238d8..d1b4a80 100644
--- a/services/companion/java/com/android/server/companion/MetricUtils.java
+++ b/services/companion/java/com/android/server/companion/MetricUtils.java
@@ -19,6 +19,7 @@
import static android.companion.AssociationRequest.DEVICE_PROFILE_APP_STREAMING;
import static android.companion.AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION;
import static android.companion.AssociationRequest.DEVICE_PROFILE_COMPUTER;
+import static android.companion.AssociationRequest.DEVICE_PROFILE_GLASSES;
import static android.companion.AssociationRequest.DEVICE_PROFILE_WATCH;
import static com.android.internal.util.FrameworkStatsLog.CDM_ASSOCIATION_ACTION;
@@ -27,6 +28,7 @@
import static com.android.internal.util.FrameworkStatsLog.CDM_ASSOCIATION_ACTION__DEVICE_PROFILE__DEVICE_PROFILE_APP_STREAMING;
import static com.android.internal.util.FrameworkStatsLog.CDM_ASSOCIATION_ACTION__DEVICE_PROFILE__DEVICE_PROFILE_AUTO_PROJECTION;
import static com.android.internal.util.FrameworkStatsLog.CDM_ASSOCIATION_ACTION__DEVICE_PROFILE__DEVICE_PROFILE_COMPUTER;
+import static com.android.internal.util.FrameworkStatsLog.CDM_ASSOCIATION_ACTION__DEVICE_PROFILE__DEVICE_PROFILE_GLASSES;
import static com.android.internal.util.FrameworkStatsLog.CDM_ASSOCIATION_ACTION__DEVICE_PROFILE__DEVICE_PROFILE_NULL;
import static com.android.internal.util.FrameworkStatsLog.CDM_ASSOCIATION_ACTION__DEVICE_PROFILE__DEVICE_PROFILE_WATCH;
import static com.android.internal.util.FrameworkStatsLog.write;
@@ -59,6 +61,10 @@
DEVICE_PROFILE_COMPUTER,
CDM_ASSOCIATION_ACTION__DEVICE_PROFILE__DEVICE_PROFILE_COMPUTER
);
+ map.put(
+ DEVICE_PROFILE_GLASSES,
+ CDM_ASSOCIATION_ACTION__DEVICE_PROFILE__DEVICE_PROFILE_GLASSES
+ );
METRIC_DEVICE_PROFILE = unmodifiableMap(map);
}
diff --git a/services/companion/java/com/android/server/companion/PermissionsUtils.java b/services/companion/java/com/android/server/companion/PermissionsUtils.java
index a41ac03..27c45d8 100644
--- a/services/companion/java/com/android/server/companion/PermissionsUtils.java
+++ b/services/companion/java/com/android/server/companion/PermissionsUtils.java
@@ -23,6 +23,7 @@
import static android.companion.AssociationRequest.DEVICE_PROFILE_APP_STREAMING;
import static android.companion.AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION;
import static android.companion.AssociationRequest.DEVICE_PROFILE_COMPUTER;
+import static android.companion.AssociationRequest.DEVICE_PROFILE_GLASSES;
import static android.companion.AssociationRequest.DEVICE_PROFILE_WATCH;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Binder.getCallingPid;
@@ -65,6 +66,7 @@
map.put(DEVICE_PROFILE_AUTOMOTIVE_PROJECTION,
Manifest.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION);
map.put(DEVICE_PROFILE_COMPUTER, Manifest.permission.REQUEST_COMPANION_PROFILE_COMPUTER);
+ map.put(DEVICE_PROFILE_GLASSES, Manifest.permission.REQUEST_COMPANION_PROFILE_GLASSES);
DEVICE_PROFILE_TO_PERMISSION = unmodifiableMap(map);
}