Merge "Introduce vendor header for selfManaged dialog" into tm-dev
This commit is contained in:
@@ -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>
|
||||||
@@ -15,14 +15,10 @@
|
|||||||
-->
|
-->
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:id="@+id/activity_confirmation"
|
android:id="@+id/activity_confirmation"
|
||||||
android:layout_width="match_parent"
|
style="@style/ContainerLayout">
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="@drawable/dialog_background"
|
<!-- A header for selfManaged devices only. -->
|
||||||
android:elevation="16dp"
|
<include layout="@layout/vendor_header" />
|
||||||
android:maxHeight="400dp"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:padding="18dp"
|
|
||||||
android:layout_gravity="center">
|
|
||||||
|
|
||||||
<!-- Do NOT change the ID of the root LinearLayout above: it's referenced in CTS tests. -->
|
<!-- Do NOT change the ID of the root LinearLayout above: it's referenced in CTS tests. -->
|
||||||
|
|
||||||
@@ -51,9 +47,9 @@
|
|||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/device_list"
|
android:id="@+id/device_list"
|
||||||
style="@android:style/Widget.Material.ListView"
|
android:layout_width="match_parent"
|
||||||
android:layout_width="match_parent"
|
android:scrollbars="vertical"
|
||||||
android:layout_height="200dp" />
|
android:layout_height="200dp" />
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
48
packages/CompanionDeviceManager/res/layout/vendor_header.xml
Normal file
48
packages/CompanionDeviceManager/res/layout/vendor_header.xml
Normal file
@@ -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>
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
<!-- ================= DEVICE_PROFILE_APP_STREAMING ================= -->
|
<!-- ================= DEVICE_PROFILE_APP_STREAMING ================= -->
|
||||||
|
|
||||||
<!-- Confirmation for associating an application with a companion device of APP_STREAMING profile (type) [CHAR LIMIT=NONE] -->
|
<!-- Confirmation for associating an application with a companion device of APP_STREAMING profile (type) [CHAR LIMIT=NONE] -->
|
||||||
<string name="title_app_streaming">Allow <strong><xliff:g id="app_name" example="Exo">%1$s</xliff:g></strong> to stream applications?</string>
|
<string name="title_app_streaming">Allow <strong><xliff:g id="app_name" example="Exo">%1$s</xliff:g></strong> 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] -->
|
<!-- 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 <strong><xliff:g id="app_name" example="Exo">%1$s</xliff:g></strong> to provide <strong><xliff:g id="device_name" example="Pixelbook Go">%2$s</xliff:g></strong> remote access to access to applications installed on this phone when connected.</string>
|
<string name="summary_app_streaming" product="default">Let <strong><xliff:g id="app_name" example="Exo">%1$s</xliff:g></strong> to provide <strong><xliff:g id="device_name" example="Pixelbook Go">%2$s</xliff:g></strong> 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] -->
|
<!-- 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 <strong><xliff:g id="app_name" example="Exo">%1$s</xliff:g></strong> to provide <strong><xliff:g id="device_name" example="Pixelbook Go">%2$s</xliff:g></strong> remote access to access to applications installed on this device when connected.</string>
|
<string name="summary_app_streaming" product="device">Let <strong><xliff:g id="app_name" example="Exo">%1$s</xliff:g></strong> to provide <strong><xliff:g id="device_name" example="Pixelbook Go">%2$s</xliff:g></strong> 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 ================= -->
|
<!-- ================= DEVICE_PROFILE_AUTOMOTIVE_PROJECTION ================= -->
|
||||||
|
|
||||||
<!-- Confirmation for associating an application with a companion device of AUTOMOTIVE_PROJECTION profile (type) [CHAR LIMIT=NONE] -->
|
<!-- 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] -->
|
<!-- 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>
|
<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 ================= -->
|
<!-- ================= null profile ================= -->
|
||||||
|
|
||||||
<!-- A noun for a companion device with unspecified profile (type) [CHAR LIMIT=30] -->
|
<!-- 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] -->
|
<!-- Negative button for the device-app association consent dialog [CHAR LIMIT=30] -->
|
||||||
<string name="consent_no">Don\u2019t allow</string>
|
<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 ==================== -->
|
<!-- ================== System data transfer ==================== -->
|
||||||
<!-- Title of the permission sync confirmation dialog. [CHAR LIMIT=60] -->
|
<!-- Title of the permission sync confirmation dialog. [CHAR LIMIT=60] -->
|
||||||
<string name="permission_sync_confirmation_title">Transfer app permissions to your
|
<string name="permission_sync_confirmation_title">Transfer app permissions to your
|
||||||
|
|||||||
38
packages/CompanionDeviceManager/res/values/styles.xml
Normal file
38
packages/CompanionDeviceManager/res/values/styles.xml
Normal file
@@ -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>
|
||||||
@@ -26,6 +26,8 @@ import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService
|
|||||||
import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService.DiscoveryState.FINISHED_TIMEOUT;
|
import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService.DiscoveryState.FINISHED_TIMEOUT;
|
||||||
import static com.android.companiondevicemanager.Utils.getApplicationLabel;
|
import static com.android.companiondevicemanager.Utils.getApplicationLabel;
|
||||||
import static com.android.companiondevicemanager.Utils.getHtmlFromResources;
|
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 com.android.companiondevicemanager.Utils.prepareResultReceiverForIpc;
|
||||||
|
|
||||||
import static java.util.Objects.requireNonNull;
|
import static java.util.Objects.requireNonNull;
|
||||||
@@ -38,6 +40,7 @@ import android.companion.CompanionDeviceManager;
|
|||||||
import android.companion.IAssociationRequestCallback;
|
import android.companion.IAssociationRequestCallback;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
import android.net.MacAddress;
|
import android.net.MacAddress;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
@@ -47,9 +50,14 @@ import android.text.Spanned;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Button;
|
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 android.widget.TextView;
|
||||||
|
|
||||||
import androidx.fragment.app.FragmentActivity;
|
import androidx.fragment.app.FragmentActivity;
|
||||||
|
import androidx.fragment.app.FragmentManager;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
@@ -59,7 +67,8 @@ import java.util.List;
|
|||||||
* A CompanionDevice activity response for showing the available
|
* A CompanionDevice activity response for showing the available
|
||||||
* nearby devices to be associated with.
|
* 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 boolean DEBUG = false;
|
||||||
private static final String TAG = CompanionDeviceActivity.class.getSimpleName();
|
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_ASSOCIATION_REQUEST = "association_request";
|
||||||
private static final String EXTRA_RESULT_RECEIVER = "result_receiver";
|
private static final String EXTRA_RESULT_RECEIVER = "result_receiver";
|
||||||
|
|
||||||
|
private static final String FRAGMENT_DIALOG_TAG = "fragment_dialog";
|
||||||
|
|
||||||
// Activity result: Internal Error.
|
// Activity result: Internal Error.
|
||||||
private static final int RESULT_INTERNAL_ERROR = 2;
|
private static final int RESULT_INTERNAL_ERROR = 2;
|
||||||
|
|
||||||
@@ -91,6 +102,11 @@ public class CompanionDeviceActivity extends FragmentActivity {
|
|||||||
private TextView mTitle;
|
private TextView mTitle;
|
||||||
private TextView mSummary;
|
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
|
// Progress indicator is only shown while we are looking for the first suitable device for a
|
||||||
// "regular" (ie. not self-managed) association.
|
// "regular" (ie. not self-managed) association.
|
||||||
private View mProgressIndicator;
|
private View mProgressIndicator;
|
||||||
@@ -98,6 +114,11 @@ public class CompanionDeviceActivity extends FragmentActivity {
|
|||||||
// Present for self-managed association requests and "single-device" regular association
|
// Present for self-managed association requests and "single-device" regular association
|
||||||
// regular.
|
// regular.
|
||||||
private Button mButtonAllow;
|
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
|
// The recycler view is only shown for multiple-device regular association request, after
|
||||||
// at least one matching device is found.
|
// at least one matching device is found.
|
||||||
@@ -211,15 +232,25 @@ public class CompanionDeviceActivity extends FragmentActivity {
|
|||||||
|
|
||||||
setContentView(R.layout.activity_confirmation);
|
setContentView(R.layout.activity_confirmation);
|
||||||
|
|
||||||
|
mAssociationConfirmationDialog = findViewById(R.id.activity_confirmation);
|
||||||
|
mVendorHeader = findViewById(R.id.vendor_header);
|
||||||
|
|
||||||
mTitle = findViewById(R.id.title);
|
mTitle = findViewById(R.id.title);
|
||||||
mSummary = findViewById(R.id.summary);
|
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);
|
mRecyclerView = findViewById(R.id.device_list);
|
||||||
mAdapter = new DeviceListAdapter(this, this::onListItemClick);
|
mAdapter = new DeviceListAdapter(this, this::onListItemClick);
|
||||||
|
|
||||||
mButtonAllow = findViewById(R.id.btn_positive);
|
mButtonAllow = findViewById(R.id.btn_positive);
|
||||||
|
mButtonNotAllow = findViewById(R.id.btn_negative);
|
||||||
|
|
||||||
mButtonAllow.setOnClickListener(this::onPositiveButtonClick);
|
mButtonAllow.setOnClickListener(this::onPositiveButtonClick);
|
||||||
findViewById(R.id.btn_negative).setOnClickListener(this::onNegativeButtonClick);
|
mButtonNotAllow.setOnClickListener(this::onNegativeButtonClick);
|
||||||
|
mVendorHeaderButton.setOnClickListener(this::onShowHelperDialog);
|
||||||
|
|
||||||
if (mRequest.isSelfManaged()) {
|
if (mRequest.isSelfManaged()) {
|
||||||
initUiForSelfManagedAssociation(appLabel);
|
initUiForSelfManagedAssociation(appLabel);
|
||||||
@@ -321,11 +352,24 @@ public class CompanionDeviceActivity extends FragmentActivity {
|
|||||||
private void initUiForSelfManagedAssociation(CharSequence appLabel) {
|
private void initUiForSelfManagedAssociation(CharSequence appLabel) {
|
||||||
if (DEBUG) Log.i(TAG, "initUiFor_SelfManaged_Association()");
|
if (DEBUG) Log.i(TAG, "initUiFor_SelfManaged_Association()");
|
||||||
|
|
||||||
final CharSequence deviceName = mRequest.getDisplayName(); // "<device>";
|
final CharSequence deviceName = mRequest.getDisplayName();
|
||||||
final String deviceProfile = mRequest.getDeviceProfile(); // DEVICE_PROFILE_APP_STREAMING;
|
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 title;
|
||||||
final Spanned summary;
|
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) {
|
switch (deviceProfile) {
|
||||||
case DEVICE_PROFILE_APP_STREAMING:
|
case DEVICE_PROFILE_APP_STREAMING:
|
||||||
title = getHtmlFromResources(this, R.string.title_app_streaming, appLabel);
|
title = getHtmlFromResources(this, R.string.title_app_streaming, appLabel);
|
||||||
@@ -348,10 +392,14 @@ public class CompanionDeviceActivity extends FragmentActivity {
|
|||||||
default:
|
default:
|
||||||
throw new RuntimeException("Unsupported profile " + deviceProfile);
|
throw new RuntimeException("Unsupported profile " + deviceProfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
mTitle.setText(title);
|
mTitle.setText(title);
|
||||||
mSummary.setText(summary);
|
mSummary.setText(summary);
|
||||||
|
mVendorHeaderImage.setImageDrawable(vendorIcon);
|
||||||
|
mVendorHeaderName.setText(vendorName);
|
||||||
|
|
||||||
mRecyclerView.setVisibility(View.GONE);
|
mRecyclerView.setVisibility(View.GONE);
|
||||||
|
mVendorHeader.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initUiForSingleDevice(CharSequence appLabel) {
|
private void initUiForSingleDevice(CharSequence appLabel) {
|
||||||
@@ -370,6 +418,7 @@ public class CompanionDeviceActivity extends FragmentActivity {
|
|||||||
String deviceProfile, CharSequence appLabel) {
|
String deviceProfile, CharSequence appLabel) {
|
||||||
// Ignore "empty" scan reports.
|
// Ignore "empty" scan reports.
|
||||||
if (deviceFilterPairs.isEmpty()) return;
|
if (deviceFilterPairs.isEmpty()) return;
|
||||||
|
|
||||||
mSelectedDevice = requireNonNull(deviceFilterPairs.get(0));
|
mSelectedDevice = requireNonNull(deviceFilterPairs.get(0));
|
||||||
|
|
||||||
final String deviceName = mSelectedDevice.getDisplayName();
|
final String deviceName = mSelectedDevice.getDisplayName();
|
||||||
@@ -464,6 +513,17 @@ public class CompanionDeviceActivity extends FragmentActivity {
|
|||||||
cancel(false);
|
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() {
|
private boolean isDone() {
|
||||||
return mApproved || mCancelled;
|
return mApproved || mCancelled;
|
||||||
}
|
}
|
||||||
@@ -482,4 +542,14 @@ public class CompanionDeviceActivity extends FragmentActivity {
|
|||||||
onAssociationCreated(association);
|
onAssociationCreated(association);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onShowHelperDialogFailed() {
|
||||||
|
setResultAndFinish(null, RESULT_INTERNAL_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onHelperDialogDismissed() {
|
||||||
|
mAssociationConfirmationDialog.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,6 +21,9 @@ import android.annotation.StringRes;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.PackageManager;
|
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.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
@@ -32,6 +35,10 @@ import android.text.Spanned;
|
|||||||
* Utilities.
|
* Utilities.
|
||||||
*/
|
*/
|
||||||
class Utils {
|
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
|
* Convert an instance of a "locally-defined" ResultReceiver to an instance of
|
||||||
@@ -60,6 +67,12 @@ class Utils {
|
|||||||
return packageManager.getApplicationLabel(appInfo);
|
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(
|
static Spanned getHtmlFromResources(
|
||||||
@NonNull Context context, @StringRes int resId, CharSequence... formatArgs) {
|
@NonNull Context context, @StringRes int resId, CharSequence... formatArgs) {
|
||||||
final String[] escapedArgs = new String[formatArgs.length];
|
final String[] escapedArgs = new String[formatArgs.length];
|
||||||
@@ -70,6 +83,44 @@ class Utils {
|
|||||||
return Html.fromHtml(plain, 0);
|
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) {
|
static void runOnMainThread(Runnable runnable) {
|
||||||
if (Thread.currentThread() == Looper.getMainLooper().getThread()) {
|
if (Thread.currentThread() == Looper.getMainLooper().getThread()) {
|
||||||
runnable.run();
|
runnable.run();
|
||||||
|
|||||||
Reference in New Issue
Block a user