Merge "Introduce vendor header for selfManaged dialog" into tm-dev am: 3dee9e9f0c
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17035337 Change-Id: I9abdce70effd6dfec0aa33aa73b5c1f252d91b93
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"
|
||||
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>
|
||||
|
||||
|
||||
@@ -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 ================= -->
|
||||
|
||||
<!-- 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] -->
|
||||
<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] -->
|
||||
<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 ================= -->
|
||||
|
||||
<!-- 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
|
||||
|
||||
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.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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.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();
|
||||
|
||||
Reference in New Issue
Block a user