summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/CompanionDeviceManager/res/drawable/helper_ok_button.xml22
-rw-r--r--packages/CompanionDeviceManager/res/layout/activity_confirmation.xml18
-rw-r--r--packages/CompanionDeviceManager/res/layout/helper_confirmation.xml63
-rw-r--r--packages/CompanionDeviceManager/res/layout/vendor_header.xml48
-rw-r--r--packages/CompanionDeviceManager/res/values/strings.xml20
-rw-r--r--packages/CompanionDeviceManager/res/values/styles.xml38
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java80
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionVendorHelperDialogFragment.java149
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java51
9 files changed, 472 insertions, 17 deletions
diff --git a/packages/CompanionDeviceManager/res/drawable/helper_ok_button.xml b/packages/CompanionDeviceManager/res/drawable/helper_ok_button.xml
new file mode 100644
index 000000000000..f9ec5d0dce55
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/drawable/helper_ok_button.xml
@@ -0,0 +1,22 @@
+<!--
+ ~ 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.
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@android:color/system_accent1_100"/>
+ <corners android:topLeftRadius="16dp" android:topRightRadius="16dp"
+ android:bottomLeftRadius="16dp" android:bottomRightRadius="16dp"/>
+</shape> \ 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 70cbfdf5cefc..f30dadffa788 100644
--- a/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
+++ b/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
@@ -15,14 +15,10 @@
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_confirmation"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="@drawable/dialog_background"
- android:elevation="16dp"
- android:maxHeight="400dp"
- android:orientation="vertical"
- android:padding="18dp"
- android:layout_gravity="center">
+ style="@style/ContainerLayout">
+
+ <!-- A header for selfManaged devices only. -->
+ <include layout="@layout/vendor_header" />
<!-- Do NOT change the ID of the root LinearLayout above: it's referenced in CTS tests. -->
@@ -51,9 +47,9 @@
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/device_list"
- style="@android:style/Widget.Material.ListView"
- android:layout_width="match_parent"
- android:layout_height="200dp" />
+ android:layout_width="match_parent"
+ android:scrollbars="vertical"
+ android:layout_height="200dp" />
</RelativeLayout>
diff --git a/packages/CompanionDeviceManager/res/layout/helper_confirmation.xml b/packages/CompanionDeviceManager/res/layout/helper_confirmation.xml
new file mode 100644
index 000000000000..8fd1fb0de891
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/layout/helper_confirmation.xml
@@ -0,0 +1,63 @@
+<!--
+ ~ 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.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/helper_confirmation"
+ android:theme="@style/ChooserActivity"
+ style="@style/ContainerLayout">
+
+ <ImageView
+ android:id="@+id/app_icon"
+ android:layout_width="match_parent"
+ android:layout_height="32dp"
+ android:gravity="center"
+ android:layout_marginBottom="12dp"
+ android:layout_marginTop="1dp"/>
+
+ <TextView
+ android:id="@+id/helper_title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:paddingHorizontal="12dp"
+ style="@*android:style/TextAppearance.Widget.Toolbar.Title"
+ android:textSize="20sp" />
+
+ <TextView
+ android:id="@+id/helper_summary"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="12dp"
+ android:layout_marginLeft="20dp"
+ android:layout_marginBottom="24dp"
+ android:gravity="start"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="14sp" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:gravity="end">
+
+ <Button
+ android:id="@+id/btn_ok"
+ style="@style/VendorHelperOkButton"
+ android:text="@string/consent_ok" />
+
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/packages/CompanionDeviceManager/res/layout/vendor_header.xml b/packages/CompanionDeviceManager/res/layout/vendor_header.xml
new file mode 100644
index 000000000000..d04eadfb62f4
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/layout/vendor_header.xml
@@ -0,0 +1,48 @@
+<!--
+ ~ 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.
+ -->
+
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/vendor_header"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:layout_gravity="center"
+ android:layout_marginBottom="16dp"
+ android:visibility="gone" >
+
+ <ImageView
+ android:id="@+id/vendor_header_image"
+ android:layout_width="31dp"
+ android:layout_height="32dp" />
+
+ <TextView
+ android:id="@+id/vendor_header_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="20dp"
+ android:layout_marginTop="5dp"
+ android:layout_toRightOf="@+id/header_image" />
+
+ <ImageButton
+ android:id="@+id/vendor_header_button"
+ style="?android:attr/actionOverflowButtonStyle"
+ android:layout_width="31dp"
+ android:layout_height="32dp"
+ android:layout_marginLeft="100dp"
+ android:layout_alignParentRight="true" />
+
+</RelativeLayout> \ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/values/strings.xml b/packages/CompanionDeviceManager/res/values/strings.xml
index f32f2cd80c47..9626751679e1 100644
--- a/packages/CompanionDeviceManager/res/values/strings.xml
+++ b/packages/CompanionDeviceManager/res/values/strings.xml
@@ -39,7 +39,7 @@
<!-- ================= DEVICE_PROFILE_APP_STREAMING ================= -->
<!-- Confirmation for associating an application with a companion device of APP_STREAMING profile (type) [CHAR LIMIT=NONE] -->
- <string name="title_app_streaming">Allow &lt;strong&gt;<xliff:g id="app_name" example="Exo">%1$s</xliff:g>&lt;/strong&gt; to stream applications?</string>
+ <string name="title_app_streaming">Allow &lt;strong&gt;<xliff:g id="app_name" example="Exo">%1$s</xliff:g>&lt;/strong&gt; to access this information for your phone</string>
<!-- Description of the privileges the application will get if associated with the companion device of APP_STREAMING profile (type) [CHAR LIMIT=NONE] -->
<string name="summary_app_streaming" product="default">Let &lt;strong&gt;<xliff:g id="app_name" example="Exo">%1$s</xliff:g>&lt;/strong&gt; to provide &lt;strong&gt;<xliff:g id="device_name" example="Pixelbook Go">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this phone when connected.</string>
@@ -50,6 +50,12 @@
<!-- Description of the privileges the application will get if associated with the companion device of APP_STREAMING profile (type) [CHAR LIMIT=NONE] -->
<string name="summary_app_streaming" product="device">Let &lt;strong&gt;<xliff:g id="app_name" example="Exo">%1$s</xliff:g>&lt;/strong&gt; to provide &lt;strong&gt;<xliff:g id="device_name" example="Pixelbook Go">%2$s</xliff:g>&lt;/strong&gt; remote access to access to applications installed on this device when connected.</string>
+ <!-- Title of the helper dialog for APP_STREAMING profile [CHAR LIMIT=30]. -->
+ <string name="helper_title_app_streaming">Cross-device services</string>
+
+ <!-- Description of the helper dialog for APP_STREAMING profile. [CHAR LIMIT=NONE] -->
+ <string name="helper_summary_app_streaming">This service is used to stream apps between your devices</string>
+
<!-- ================= DEVICE_PROFILE_AUTOMOTIVE_PROJECTION ================= -->
<!-- Confirmation for associating an application with a companion device of AUTOMOTIVE_PROJECTION profile (type) [CHAR LIMIT=NONE] -->
@@ -66,6 +72,15 @@
<!-- Description of the privileges the application will get if associated with the companion device of COMPUTER profile (type) [CHAR LIMIT=NONE] -->
<string name="summary_computer"></string>
+ <!-- Title of the helper dialog for COMPUTER profile [CHAR LIMIT=30]. -->
+ <string name="helper_title_computer">Google Play services</string>
+
+ <!-- Description of the helper dialog for COMPUTER profile. [CHAR LIMIT=NONE] -->
+ <string name="helper_summary_computer" product="default">This service shares photos, media, and notifications form your phone to other devices</string>
+
+ <!-- Description of the helper dialog for COMPUTER profile. [CHAR LIMIT=NONE] -->
+ <string name="helper_summary_computer" product="tablet">This service shares photos, media, and notifications form your phone to other devices</string>
+
<!-- ================= null profile ================= -->
<!-- A noun for a companion device with unspecified profile (type) [CHAR LIMIT=30] -->
@@ -82,6 +97,9 @@
<!-- Negative button for the device-app association consent dialog [CHAR LIMIT=30] -->
<string name="consent_no">Don\u2019t allow</string>
+ <!-- Ok button for the helper consent dialog [CHAR LIMIT=30] -->
+ <string name="consent_ok">OK</string>
+
<!-- ================== System data transfer ==================== -->
<!-- Title of the permission sync confirmation dialog. [CHAR LIMIT=60] -->
<string name="permission_sync_confirmation_title">Transfer app permissions to your
diff --git a/packages/CompanionDeviceManager/res/values/styles.xml b/packages/CompanionDeviceManager/res/values/styles.xml
new file mode 100644
index 000000000000..bba45e9ecf0f
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/values/styles.xml
@@ -0,0 +1,38 @@
+<!--
+ ~ 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.
+ -->
+
+<resources>
+ <style name="ContainerLayout">
+ <item name="android:padding">18dp</item>
+ <item name="android:elevation">16dp</item>
+ <item name="android:maxHeight">400dp</item>
+ <item name="android:orientation">vertical</item>
+ <item name="android:layout_gravity">center</item>
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:background">@drawable/dialog_background</item>
+ </style>
+
+ <style name="VendorHelperOkButton"
+ parent="@android:style/Widget.Material.Button.Borderless.Colored">
+ <item name="android:layout_width">50dp</item>
+ <item name="android:layout_height">35dp</item>
+ <item name="android:layout_marginTop">20dp</item>
+ <item name="android:textColor">@android:color/system_neutral1_900</item>
+ <item name="android:background">@drawable/helper_ok_button</item>
+ </style>
+
+</resources> \ No newline at end of file
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index ae0c8ccdf006..0fba250b200a 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -26,6 +26,8 @@ import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService
import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService.DiscoveryState.FINISHED_TIMEOUT;
import static com.android.companiondevicemanager.Utils.getApplicationLabel;
import static com.android.companiondevicemanager.Utils.getHtmlFromResources;
+import static com.android.companiondevicemanager.Utils.getVendorHeaderIcon;
+import static com.android.companiondevicemanager.Utils.getVendorHeaderName;
import static com.android.companiondevicemanager.Utils.prepareResultReceiverForIpc;
import static java.util.Objects.requireNonNull;
@@ -38,6 +40,7 @@ import android.companion.CompanionDeviceManager;
import android.companion.IAssociationRequestCallback;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
import android.net.MacAddress;
import android.os.Bundle;
import android.os.Handler;
@@ -47,9 +50,14 @@ import android.text.Spanned;
import android.util.Log;
import android.view.View;
import android.widget.Button;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.fragment.app.FragmentActivity;
+import androidx.fragment.app.FragmentManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@@ -59,7 +67,8 @@ import java.util.List;
* A CompanionDevice activity response for showing the available
* nearby devices to be associated with.
*/
-public class CompanionDeviceActivity extends FragmentActivity {
+public class CompanionDeviceActivity extends FragmentActivity implements
+ CompanionVendorHelperDialogFragment.CompanionVendorHelperDialogListener {
private static final boolean DEBUG = false;
private static final String TAG = CompanionDeviceActivity.class.getSimpleName();
@@ -72,6 +81,8 @@ public class CompanionDeviceActivity extends FragmentActivity {
private static final String EXTRA_ASSOCIATION_REQUEST = "association_request";
private static final String EXTRA_RESULT_RECEIVER = "result_receiver";
+ private static final String FRAGMENT_DIALOG_TAG = "fragment_dialog";
+
// Activity result: Internal Error.
private static final int RESULT_INTERNAL_ERROR = 2;
@@ -91,6 +102,11 @@ public class CompanionDeviceActivity extends FragmentActivity {
private TextView mTitle;
private TextView mSummary;
+ // Only present for selfManaged devices.
+ private ImageView mVendorHeaderImage;
+ private TextView mVendorHeaderName;
+ private ImageButton mVendorHeaderButton;
+
// Progress indicator is only shown while we are looking for the first suitable device for a
// "regular" (ie. not self-managed) association.
private View mProgressIndicator;
@@ -98,6 +114,11 @@ public class CompanionDeviceActivity extends FragmentActivity {
// Present for self-managed association requests and "single-device" regular association
// regular.
private Button mButtonAllow;
+ // Present for all associations.
+ private Button mButtonNotAllow;
+
+ private LinearLayout mAssociationConfirmationDialog;
+ private RelativeLayout mVendorHeader;
// The recycler view is only shown for multiple-device regular association request, after
// at least one matching device is found.
@@ -211,15 +232,25 @@ public class CompanionDeviceActivity extends FragmentActivity {
setContentView(R.layout.activity_confirmation);
+ mAssociationConfirmationDialog = findViewById(R.id.activity_confirmation);
+ mVendorHeader = findViewById(R.id.vendor_header);
+
mTitle = findViewById(R.id.title);
mSummary = findViewById(R.id.summary);
+ mVendorHeaderImage = findViewById(R.id.vendor_header_image);
+ 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);
mButtonAllow = findViewById(R.id.btn_positive);
+ mButtonNotAllow = findViewById(R.id.btn_negative);
+
mButtonAllow.setOnClickListener(this::onPositiveButtonClick);
- findViewById(R.id.btn_negative).setOnClickListener(this::onNegativeButtonClick);
+ mButtonNotAllow.setOnClickListener(this::onNegativeButtonClick);
+ mVendorHeaderButton.setOnClickListener(this::onShowHelperDialog);
if (mRequest.isSelfManaged()) {
initUiForSelfManagedAssociation(appLabel);
@@ -321,11 +352,24 @@ public class CompanionDeviceActivity extends FragmentActivity {
private void initUiForSelfManagedAssociation(CharSequence appLabel) {
if (DEBUG) Log.i(TAG, "initUiFor_SelfManaged_Association()");
- final CharSequence deviceName = mRequest.getDisplayName(); // "<device>";
- final String deviceProfile = mRequest.getDeviceProfile(); // DEVICE_PROFILE_APP_STREAMING;
-
+ final CharSequence deviceName = mRequest.getDisplayName();
+ final String deviceProfile = mRequest.getDeviceProfile();
+ final String packageName = mRequest.getPackageName();
+ final int userId = mRequest.getUserId();
+ final Drawable vendorIcon;
+ final CharSequence vendorName;
final Spanned title;
final Spanned summary;
+
+ try {
+ vendorIcon = getVendorHeaderIcon(this, packageName, userId);
+ vendorName = getVendorHeaderName(this, packageName, userId);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Package u" + userId + "/" + packageName + " not found.");
+ setResultAndFinish(null, RESULT_INTERNAL_ERROR);
+ return;
+ }
+
switch (deviceProfile) {
case DEVICE_PROFILE_APP_STREAMING:
title = getHtmlFromResources(this, R.string.title_app_streaming, appLabel);
@@ -348,10 +392,14 @@ public class CompanionDeviceActivity extends FragmentActivity {
default:
throw new RuntimeException("Unsupported profile " + deviceProfile);
}
+
mTitle.setText(title);
mSummary.setText(summary);
+ mVendorHeaderImage.setImageDrawable(vendorIcon);
+ mVendorHeaderName.setText(vendorName);
mRecyclerView.setVisibility(View.GONE);
+ mVendorHeader.setVisibility(View.VISIBLE);
}
private void initUiForSingleDevice(CharSequence appLabel) {
@@ -370,6 +418,7 @@ public class CompanionDeviceActivity extends FragmentActivity {
String deviceProfile, CharSequence appLabel) {
// Ignore "empty" scan reports.
if (deviceFilterPairs.isEmpty()) return;
+
mSelectedDevice = requireNonNull(deviceFilterPairs.get(0));
final String deviceName = mSelectedDevice.getDisplayName();
@@ -464,6 +513,17 @@ public class CompanionDeviceActivity extends FragmentActivity {
cancel(false);
}
+ private void onShowHelperDialog(View view) {
+ FragmentManager fragmentManager = getSupportFragmentManager();
+ CompanionVendorHelperDialogFragment fragmentDialog =
+ CompanionVendorHelperDialogFragment.newInstance(mRequest.getPackageName(),
+ mRequest.getUserId(), mRequest.getDeviceProfile());
+
+ mAssociationConfirmationDialog.setVisibility(View.GONE);
+
+ fragmentDialog.show(fragmentManager, /* Tag */ FRAGMENT_DIALOG_TAG);
+ }
+
private boolean isDone() {
return mApproved || mCancelled;
}
@@ -482,4 +542,14 @@ public class CompanionDeviceActivity extends FragmentActivity {
onAssociationCreated(association);
}
};
+
+ @Override
+ public void onShowHelperDialogFailed() {
+ setResultAndFinish(null, RESULT_INTERNAL_ERROR);
+ }
+
+ @Override
+ public void onHelperDialogDismissed() {
+ mAssociationConfirmationDialog.setVisibility(View.VISIBLE);
+ }
}
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionVendorHelperDialogFragment.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionVendorHelperDialogFragment.java
new file mode 100644
index 000000000000..728e5e5d3b9e
--- /dev/null
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionVendorHelperDialogFragment.java
@@ -0,0 +1,149 @@
+/*
+ * 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.
+ */
+
+package com.android.companiondevicemanager;
+
+import static android.companion.AssociationRequest.DEVICE_PROFILE_APP_STREAMING;
+import static android.companion.AssociationRequest.DEVICE_PROFILE_COMPUTER;
+
+import static com.android.companiondevicemanager.Utils.getApplicationIcon;
+import static com.android.companiondevicemanager.Utils.getHtmlFromResources;
+
+import android.annotation.Nullable;
+import android.content.DialogInterface;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.text.Spanned;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.fragment.app.DialogFragment;
+
+/**
+ * A fragmentDialog shows additional information about selfManaged devices
+ */
+public class CompanionVendorHelperDialogFragment extends DialogFragment {
+ private static final String TAG = CompanionVendorHelperDialogFragment.class.getSimpleName();
+
+ private static final String PACKAGE_NAME_EXTRA = "packageName";
+ private static final String DEVICE_PROFILE_EXTRA = "deviceProfile";
+ private static final String USER_ID_EXTRA = "userId";
+
+ private CompanionVendorHelperDialogListener mListener;
+ // Only present for selfManaged devices.
+ private TextView mTitle;
+ private TextView mSummary;
+ private ImageView mAppIcon;
+ private Button mButton;
+
+ interface CompanionVendorHelperDialogListener {
+ void onShowHelperDialogFailed();
+ void onHelperDialogDismissed();
+ }
+
+ private CompanionVendorHelperDialogFragment() {}
+
+ static CompanionVendorHelperDialogFragment newInstance(String packageName,
+ int userId, String deviceProfile) {
+ CompanionVendorHelperDialogFragment fragmentDialog =
+ new CompanionVendorHelperDialogFragment();
+
+ Bundle bundle = new Bundle();
+ bundle.putString(PACKAGE_NAME_EXTRA, packageName);
+ bundle.putInt(USER_ID_EXTRA, userId);
+ bundle.putString(DEVICE_PROFILE_EXTRA, deviceProfile);
+ fragmentDialog.setArguments(bundle);
+
+ return fragmentDialog;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mListener = (CompanionVendorHelperDialogListener) getActivity();
+ // Hide the title bar in the dialog.
+ setStyle(STYLE_NO_TITLE, /* Theme */0);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.helper_confirmation, container);
+ }
+
+ @Override
+ public void onDismiss(@NonNull DialogInterface dialog) {
+ super.onDismiss(dialog);
+ mListener.onHelperDialogDismissed();
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ Drawable applicationIcon;
+ String packageName = getArguments().getString(PACKAGE_NAME_EXTRA);
+ String deviceProfile = getArguments().getString(DEVICE_PROFILE_EXTRA);
+ int userId = getArguments().getInt(USER_ID_EXTRA);
+
+ try {
+ applicationIcon = getApplicationIcon(getContext(), packageName);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Package u" + userId + "/" + packageName + " not found.");
+ mListener.onShowHelperDialogFailed();
+ return;
+ }
+
+ mTitle = view.findViewById(R.id.helper_title);
+ mSummary = view.findViewById(R.id.helper_summary);
+ mAppIcon = view.findViewById(R.id.app_icon);
+ mButton = view.findViewById(R.id.btn_ok);
+
+ final Spanned title;
+ final Spanned summary;
+
+ switch (deviceProfile) {
+ case DEVICE_PROFILE_APP_STREAMING:
+ title = getHtmlFromResources(getContext(), R.string.helper_title_app_streaming);
+ summary = getHtmlFromResources(getContext(), R.string.helper_summary_app_streaming);
+ break;
+
+ case DEVICE_PROFILE_COMPUTER:
+ title = getHtmlFromResources(getContext(), R.string.helper_title_computer);
+ summary = getHtmlFromResources(getContext(), R.string.helper_summary_computer);
+ break;
+
+ default:
+ throw new RuntimeException("Unsupported profile " + deviceProfile);
+ }
+
+ mTitle.setText(title);
+ mSummary.setText(summary);
+ mAppIcon.setImageDrawable(applicationIcon);
+
+ mButton.setOnClickListener(v -> {
+ dismiss();
+ mListener.onHelperDialogDismissed();
+ });
+ }
+}
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java
index e3e563d56e8a..76bbcfb79155 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java
@@ -21,6 +21,9 @@ import android.annotation.StringRes;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.ApplicationInfoFlags;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Parcel;
@@ -32,6 +35,10 @@ import android.text.Spanned;
* Utilities.
*/
class Utils {
+ private static final String COMPANION_DEVICE_ACTIVITY_VENDOR_ICON =
+ "android.companion.vendor_icon";
+ private static final String COMPANION_DEVICE_ACTIVITY_VENDOR_NAME =
+ "android.companion.vendor_name";
/**
* Convert an instance of a "locally-defined" ResultReceiver to an instance of
@@ -60,6 +67,12 @@ class Utils {
return packageManager.getApplicationLabel(appInfo);
}
+ static @NonNull Drawable getApplicationIcon(@NonNull Context context,
+ @NonNull String packageName) throws PackageManager.NameNotFoundException {
+ final PackageManager packageManager = context.getPackageManager();
+ return packageManager.getApplicationIcon(packageName);
+ }
+
static Spanned getHtmlFromResources(
@NonNull Context context, @StringRes int resId, CharSequence... formatArgs) {
final String[] escapedArgs = new String[formatArgs.length];
@@ -70,6 +83,44 @@ class Utils {
return Html.fromHtml(plain, 0);
}
+ static @NonNull Drawable getVendorHeaderIcon(@NonNull Context context,
+ @NonNull String packageName, int userId) throws PackageManager.NameNotFoundException {
+ final ApplicationInfo appInfo = getApplicationInfo(context, packageName, userId);
+ final Bundle bundle = appInfo.metaData;
+ int resId = bundle == null ? 0 : bundle.getInt(COMPANION_DEVICE_ACTIVITY_VENDOR_ICON, 0);
+
+ if (bundle == null || resId == 0) {
+ return getApplicationIcon(context, packageName);
+ }
+
+ return context.createPackageContext(packageName, /* flags= */ 0).getDrawable(resId);
+ }
+
+ static CharSequence getVendorHeaderName(@NonNull Context context,
+ @NonNull String packageName, int userId) throws PackageManager.NameNotFoundException {
+ final ApplicationInfo appInfo = getApplicationInfo(context, packageName, userId);
+ final Bundle bundle = appInfo.metaData;
+
+ if (bundle == null) {
+ return "";
+ }
+
+ return appInfo.metaData.getCharSequence(COMPANION_DEVICE_ACTIVITY_VENDOR_NAME, "");
+ }
+
+ /**
+ * Getting ApplicationInfo from meta-data.
+ */
+ private static @NonNull ApplicationInfo getApplicationInfo(@NonNull Context context,
+ @NonNull String packageName, int userId) throws PackageManager.NameNotFoundException {
+ final PackageManager packageManager = context.getPackageManager();
+ final ApplicationInfoFlags flags = ApplicationInfoFlags.of(PackageManager.GET_META_DATA);
+ final ApplicationInfo appInfo = packageManager.getApplicationInfoAsUser(
+ packageName, flags, userId);
+
+ return appInfo;
+ }
+
static void runOnMainThread(Runnable runnable) {
if (Thread.currentThread() == Looper.getMainLooper().getThread()) {
runnable.run();