App header cleanup

- Refactor the entity header layout to use LinearLayout and add id to
  content area
- Remove now unused AppHeader class
- Make entire icon+text area clickable and link to app info page
  Refactor the binding logic from bindButton to its own method.
- Remove unused MultiLinePreference

Fix: 62705377
Test: make RunSettingsRoboTests

Change-Id: I6db554695410e71b669f6fdba29d98fedc3364b9
This commit is contained in:
Fan Zhang
2017-06-30 13:14:02 -07:00
parent 08da5d84c0
commit 75bee9bf98
14 changed files with 137 additions and 224 deletions

View File

@@ -16,16 +16,24 @@
-->
<!-- Entity header -->
<RelativeLayout
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/entity_header"
style="@style/EntityHeader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="@dimen/preference_no_icon_padding_start"
android:paddingTop="24dp"
android:paddingBottom="24dp">
<LinearLayout
android:id="@+id/entity_header_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="?android:attr/selectableItemBackground"
android:orientation="horizontal"
android:paddingStart="56dp">
<ImageView
android:id="@+id/entity_header_icon"
android:layout_width="48dp"
@@ -34,40 +42,9 @@
android:layout_gravity="center_horizontal"
android:antialias="true" />
<LinearLayout
android:id="@+id/entity_header_links"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentEnd="true"
android:orientation="vertical">
<ImageButton
android:id="@android:id/button1"
style="?android:attr/actionOverflowButtonStyle"
android:layout_width="wrap_content"
android:layout_weight="1"
android:layout_height="0dp"
android:minWidth="@dimen/min_tap_target_size"
android:src="@drawable/ic_settings_24dp"
android:tint="?android:attr/colorAccent" />
<ImageButton
android:id="@android:id/button2"
style="?android:attr/actionOverflowButtonStyle"
android:layout_width="wrap_content"
android:layout_weight="1"
android:layout_height="0dp"
android:minWidth="@dimen/min_tap_target_size"
android:src="@null"
android:tint="?android:attr/colorAccent" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/entity_header_icon"
android:layout_toStartOf="@id/entity_header_links"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:orientation="vertical">
@@ -105,5 +82,34 @@
android:textColor="?android:attr/textColorSecondary" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>
<LinearLayout
android:id="@+id/entity_header_links"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageButton
android:id="@android:id/button1"
style="?android:attr/actionOverflowButtonStyle"
android:layout_width="wrap_content"
android:layout_weight="1"
android:layout_height="0dp"
android:minWidth="@dimen/min_tap_target_size"
android:src="@drawable/ic_settings_24dp"
android:tint="?android:attr/colorAccent" />
<ImageButton
android:id="@android:id/button2"
style="?android:attr/actionOverflowButtonStyle"
android:layout_width="wrap_content"
android:layout_weight="1"
android:layout_height="0dp"
android:minWidth="@dimen/min_tap_target_size"
android:src="@null"
android:tint="?android:attr/colorAccent" />
</LinearLayout>
</LinearLayout>

View File

@@ -28,9 +28,11 @@
android:orientation="horizontal">
<LinearLayout
android:id="@+id/entity_header_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="?android:attr/selectableItemBackground"
android:orientation="vertical">
<ImageView

View File

@@ -1,41 +0,0 @@
/*
* Copyright (C) 2015 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.settings;
import android.app.Fragment;
import android.content.Intent;
import android.os.Bundle;
public class AppHeader {
public static final String EXTRA_HIDE_INFO_BUTTON = "hideInfoButton";
// constant value that can be used to check return code from sub activity.
private static final int INSTALLED_APP_DETAILS = 1;
public static boolean includeAppInfo(final Fragment fragment) {
Bundle args = fragment.getArguments();
boolean showInfo = true;
if (args != null && args.getBoolean(EXTRA_HIDE_INFO_BUTTON, false)) {
showInfo = false;
}
Intent intent = fragment.getActivity().getIntent();
if (intent != null && intent.getBooleanExtra(EXTRA_HIDE_INFO_BUTTON, false)) {
showInfo = false;
}
return showInfo;
}
}

View File

@@ -1,49 +0,0 @@
/*
* Copyright (C) 2016 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.settings;
import android.content.Context;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceViewHolder;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;
public class MultiLinePreference extends Preference {
public MultiLinePreference(Context ctx, AttributeSet attrs, int defStyle) {
super(ctx, attrs, defStyle);
}
public MultiLinePreference(Context ctx, AttributeSet attrs) {
super(ctx, attrs);
}
public MultiLinePreference(Context ctx) {
super(ctx);
}
@Override
public void onBindViewHolder(PreferenceViewHolder view) {
super.onBindViewHolder(view);
TextView textView = (TextView) view.findViewById(android.R.id.title);
if (textView != null) {
textView.setSingleLine(false);
}
}
}

View File

@@ -51,7 +51,8 @@ public abstract class AppInfoWithHeader extends AppInfoBase {
.setIsInstantApp(AppUtils.isInstant(mPackageInfo.applicationInfo))
.setPackageName(mPackageName)
.setUid(mPackageInfo.applicationInfo.uid)
.setButtonActions(ActionType.ACTION_APP_INFO, ActionType.ACTION_NONE)
.setHasAppInfoLink(true)
.setButtonActions(ActionType.ACTION_NONE, ActionType.ACTION_NONE)
.done(activity, getPrefContext());
getPreferenceScreen().addPreference(pref);
}

View File

@@ -69,7 +69,6 @@ import android.widget.Button;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.os.BatterySipper;
import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.AppHeader;
import com.android.settings.DeviceAdminAdd;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
@@ -145,7 +144,7 @@ public class InstalledAppDetails extends AppInfoBase
private static final int DLG_FORCE_STOP = DLG_BASE + 1;
private static final int DLG_DISABLE = DLG_BASE + 2;
private static final int DLG_SPECIAL_DISABLE = DLG_BASE + 3;
private static final String EXTRA_HIDE_INFO_BUTTON = "hideInfoButton";
private static final String KEY_HEADER = "header_view";
private static final String KEY_INSTANT_APP_BUTTONS = "instant_app_buttons";
private static final String KEY_ACTION_BUTTONS = "action_buttons";
@@ -445,6 +444,7 @@ public class InstalledAppDetails extends AppInfoBase
EntityHeaderController.newInstance(activity, this, mHeader.findViewById(R.id.entity_header))
.setRecyclerView(getListView(), getLifecycle())
.setPackageName(mPackageName)
.setHasAppInfoLink(false)
.setButtonActions(EntityHeaderController.ActionType.ACTION_APP_PREFERENCE,
EntityHeaderController.ActionType.ACTION_NONE)
.styleActionBar(activity)
@@ -935,7 +935,7 @@ public class InstalledAppDetails extends AppInfoBase
// start new activity to manage app permissions
Intent intent = new Intent(Intent.ACTION_MANAGE_APP_PERMISSIONS);
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, mAppEntry.info.packageName);
intent.putExtra(AppHeader.EXTRA_HIDE_INFO_BUTTON, true);
intent.putExtra(EXTRA_HIDE_INFO_BUTTON, true);
try {
getActivity().startActivityForResult(intent, SUB_INFO_FRAGMENT);
} catch (ActivityNotFoundException e) {
@@ -953,7 +953,6 @@ public class InstalledAppDetails extends AppInfoBase
Bundle args = new Bundle();
args.putString(ARG_PACKAGE_NAME, appEntry.info.packageName);
args.putInt(ARG_PACKAGE_UID, appEntry.info.uid);
args.putBoolean(AppHeader.EXTRA_HIDE_INFO_BUTTON, true);
SettingsActivity sa = (SettingsActivity) caller.getActivity();
sa.startPreferencePanel(caller, fragment.getName(), args, -1, title, caller,

View File

@@ -24,7 +24,6 @@ import android.widget.ArrayAdapter;
import android.widget.Spinner;
import com.android.internal.app.procstats.ProcessStats;
import com.android.settings.AppHeader;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.SettingsPreferenceFragment;
@@ -138,7 +137,6 @@ public abstract class ProcessStatsBase extends SettingsPreferenceFragment
args.putDouble(ProcessStatsDetail.EXTRA_MAX_MEMORY_USAGE,
memInfo.usedWeight * memInfo.weightToRam);
args.putDouble(ProcessStatsDetail.EXTRA_TOTAL_SCALE, memInfo.totalScale);
args.putBoolean(AppHeader.EXTRA_HIDE_INFO_BUTTON, !includeAppInfo);
activity.startPreferencePanel(null, ProcessStatsDetail.class.getName(), args,
R.string.memory_usage, null, null, 0);
}

View File

@@ -137,7 +137,8 @@ public class ProcessStatsDetail extends SettingsPreferenceFragment {
.setUid(mApp.mUiTargetApp != null
? mApp.mUiTargetApp.uid
: UserHandle.USER_NULL)
.setButtonActions(ActionType.ACTION_APP_INFO, ActionType.ACTION_NONE)
.setHasAppInfoLink(true)
.setButtonActions(ActionType.ACTION_NONE, ActionType.ACTION_NONE)
.done(activity, getPrefContext());
getPreferenceScreen().addPreference(pref);
}

View File

@@ -338,9 +338,8 @@ public class AppDataUsage extends DataUsageBase implements Preference.OnPreferen
.newInstance(activity, this, null /* header */)
.setRecyclerView(getListView(), getLifecycle())
.setUid(uid)
.setButtonActions(showInfoButton
? EntityHeaderController.ActionType.ACTION_APP_INFO
: EntityHeaderController.ActionType.ACTION_NONE,
.setHasAppInfoLink(showInfoButton)
.setButtonActions(EntityHeaderController.ActionType.ACTION_NONE,
EntityHeaderController.ActionType.ACTION_NONE)
.setIcon(mIcon)
.setLabel(mLabel)

View File

@@ -34,7 +34,6 @@ import android.view.View;
import android.widget.Switch;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.AppHeader;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.applications.AppInfoBase;
@@ -137,6 +136,7 @@ public class AppNotificationSettings extends NotificationSettingsBase {
.setLabel(mAppRow.label)
.setPackageName(mAppRow.pkg)
.setUid(mAppRow.uid)
.setHasAppInfoLink(true)
.setButtonActions(EntityHeaderController.ActionType.ACTION_NONE,
EntityHeaderController.ActionType.ACTION_NOTIF_PREFERENCE)
.done(activity, getPrefContext());
@@ -219,7 +219,6 @@ public class AppNotificationSettings extends NotificationSettingsBase {
channelPref.setSummary(getImportanceSummary(channel));
Bundle channelArgs = new Bundle();
channelArgs.putInt(AppInfoBase.ARG_PACKAGE_UID, mUid);
channelArgs.putBoolean(AppHeader.EXTRA_HIDE_INFO_BUTTON, true);
channelArgs.putString(AppInfoBase.ARG_PACKAGE_NAME, mPkg);
channelArgs.putString(Settings.EXTRA_CHANNEL_ID, channel.getId());
Intent channelIntent = Utils.onBuildStartFragmentIntent(getActivity(),

View File

@@ -36,7 +36,6 @@ import android.view.View;
import android.widget.Switch;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.AppHeader;
import com.android.settings.R;
import com.android.settings.RingtonePreference;
import com.android.settings.Utils;
@@ -146,8 +145,9 @@ public class ChannelNotificationSettings extends NotificationSettingsBase {
.setSummary(mAppRow.label)
.setPackageName(mAppRow.pkg)
.setUid(mAppRow.uid)
.setButtonActions(EntityHeaderController.ActionType.ACTION_APP_INFO,
EntityHeaderController.ActionType.ACTION_NOTIF_PREFERENCE)
.setButtonActions(EntityHeaderController.ActionType.ACTION_NOTIF_PREFERENCE,
EntityHeaderController.ActionType.ACTION_NONE)
.setHasAppInfoLink(true)
.done(activity, getPrefContext());
getPreferenceScreen().addPreference(pref);
}
@@ -283,7 +283,6 @@ public class ChannelNotificationSettings extends NotificationSettingsBase {
mImportance = findPreference(KEY_IMPORTANCE);
Bundle channelArgs = new Bundle();
channelArgs.putInt(AppInfoBase.ARG_PACKAGE_UID, mUid);
channelArgs.putBoolean(AppHeader.EXTRA_HIDE_INFO_BUTTON, true);
channelArgs.putString(AppInfoBase.ARG_PACKAGE_NAME, mPkg);
channelArgs.putString(Settings.EXTRA_CHANNEL_ID, mChannel.getId());
mImportance.setEnabled(mSuspendedAppsAdmin == null && isChannelConfigurable(mChannel));

View File

@@ -39,7 +39,6 @@ import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import com.android.settings.AppHeader;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.applications.AppInfoBase;
@@ -59,15 +58,13 @@ import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION
public class EntityHeaderController {
@IntDef({ActionType.ACTION_NONE,
ActionType.ACTION_APP_INFO,
ActionType.ACTION_APP_PREFERENCE,
ActionType.ACTION_NOTIF_PREFERENCE})
@Retention(RetentionPolicy.SOURCE)
public @interface ActionType {
int ACTION_NONE = 0;
int ACTION_APP_INFO = 1;
int ACTION_APP_PREFERENCE = 2;
int ACTION_NOTIF_PREFERENCE = 3;
int ACTION_APP_PREFERENCE = 1;
int ACTION_NOTIF_PREFERENCE = 2;
}
public static final String PREF_KEY_APP_HEADER = "pref_app_header";
@@ -94,6 +91,8 @@ public class EntityHeaderController {
@ActionType
private int mAction2;
private boolean mHasAppInfoLink;
private boolean mIsInstantApp;
/**
@@ -177,6 +176,11 @@ public class EntityHeaderController {
return this;
}
public EntityHeaderController setHasAppInfoLink(boolean hasAppInfoLink) {
mHasAppInfoLink = hasAppInfoLink;
return this;
}
public EntityHeaderController setButtonActions(@ActionType int action1,
@ActionType int action2) {
mAction1 = action1;
@@ -243,14 +247,40 @@ public class EntityHeaderController {
* Only binds entity header with button actions.
*/
public EntityHeaderController bindHeaderButtons() {
ImageButton button1 = mHeader.findViewById(android.R.id.button1);
ImageButton button2 = mHeader.findViewById(android.R.id.button2);
final View entityHeaderContent = mHeader.findViewById(R.id.entity_header_content);
final ImageButton button1 = mHeader.findViewById(android.R.id.button1);
final ImageButton button2 = mHeader.findViewById(android.R.id.button2);
bindAppInfoLink(entityHeaderContent);
bindButton(button1, mAction1);
bindButton(button2, mAction2);
return this;
}
private void bindAppInfoLink(View entityHeaderContent) {
if (!mHasAppInfoLink) {
// Caller didn't ask for app link, skip.
return;
}
if (entityHeaderContent == null
|| mPackageName == null
|| mPackageName.equals(Utils.OS_PKG)
|| mUid == UserHandle.USER_NULL) {
Log.w(TAG, "Missing ingredients to build app info link, skip");
return;
}
entityHeaderContent.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AppInfoBase.startAppInfoFragment(
InstalledAppDetails.class, R.string.application_info_label,
mPackageName, mUid, mFragment, 0 /* request */,
mMetricsCategory);
}
});
return;
}
public EntityHeaderController styleActionBar(Activity activity) {
if (activity == null) {
Log.w(TAG, "No activity, cannot style actionbar.");
@@ -284,29 +314,6 @@ public class EntityHeaderController {
return;
}
switch (action) {
case ActionType.ACTION_APP_INFO: {
if (mPackageName == null || mPackageName.equals(Utils.OS_PKG)
|| mUid == UserHandle.USER_NULL
|| !AppHeader.includeAppInfo(mFragment)) {
button.setVisibility(View.GONE);
} else {
button.setContentDescription(
mAppContext.getString(R.string.application_info_label));
button.setImageResource(com.android.settings.R.drawable.ic_info);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AppInfoBase.startAppInfoFragment(
InstalledAppDetails.class, R.string.application_info_label,
mPackageName, mUid, mFragment, 0 /* request */,
mMetricsCategory);
}
});
button.setVisibility(View.VISIBLE);
}
return;
}
case ActionType.ACTION_NOTIF_PREFERENCE: {
if (mAppNotifPrefIntent == null) {
button.setVisibility(View.GONE);

View File

@@ -25,13 +25,12 @@ import android.support.v7.preference.PreferenceScreen;
import android.util.ArraySet;
import android.view.View;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
import com.android.settings.applications.PackageManagerWrapper;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.ShadowEntityHeaderController;
import com.android.settings.widget.EntityHeaderController;
import com.android.settings.widget.EntityHeaderController.ActionType;
import com.android.settingslib.AppItem;
import org.junit.After;
@@ -46,6 +45,7 @@ import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
@@ -96,7 +96,7 @@ public class AppDataUsageTest {
mFragment.onViewCreated(new View(RuntimeEnvironment.application), new Bundle());
verify(mHeaderController).setButtonActions(ActionType.ACTION_NONE, ActionType.ACTION_NONE);
verify(mHeaderController).setHasAppInfoLink(false);
}
@Test
@@ -119,6 +119,7 @@ public class AppDataUsageTest {
ShadowEntityHeaderController.setUseMock(mHeaderController);
when(mHeaderController.setRecyclerView(any(), any())).thenReturn(mHeaderController);
when(mHeaderController.setUid(fakeUserId)).thenReturn(mHeaderController);
when(mHeaderController.setHasAppInfoLink(anyBoolean())).thenReturn(mHeaderController);
doReturn(mock(PreferenceManager.class, RETURNS_DEEP_STUBS))
.when(mFragment)
@@ -128,7 +129,7 @@ public class AppDataUsageTest {
mFragment.onViewCreated(new View(RuntimeEnvironment.application), new Bundle());
verify(mHeaderController)
.setButtonActions(ActionType.ACTION_APP_INFO, ActionType.ACTION_NONE);
.setHasAppInfoLink(true);
verify(mHeaderController)
.setUid(fakeUserId);
}

View File

@@ -53,6 +53,7 @@ import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -182,14 +183,17 @@ public class EntityHeaderControllerTest {
}
@Test
public void bindButton_noAppInfo_shouldNotShowButton() {
public void bindButton_noAppInfo_shouldNotAttachClickListener() {
final View appLinks = mLayoutInflater
.inflate(R.layout.settings_entity_header, null /* root */);
final Activity activity = mock(Activity.class);
when(mFragment.getActivity()).thenReturn(activity);
mController = EntityHeaderController.newInstance(mActivity, mFragment, appLinks);
mController.setPackageName(null)
.setHasAppInfoLink(true)
.setButtonActions(
EntityHeaderController.ActionType.ACTION_APP_INFO,
EntityHeaderController.ActionType.ACTION_NONE,
EntityHeaderController.ActionType.ACTION_NONE);
mController.done(mActivity);
@@ -197,45 +201,32 @@ public class EntityHeaderControllerTest {
.isEqualTo(View.GONE);
assertThat(appLinks.findViewById(android.R.id.button2).getVisibility())
.isEqualTo(View.GONE);
appLinks.findViewById(R.id.entity_header_content).performClick();
verify(mFragment, never()).getActivity();
verify(activity, never()).startActivity(any(Intent.class));
}
@Test
public void bindButton_hasAppInfo_shouldShowButton() {
public void bindButton_hasAppInfo_shouldAttachClickListener() {
final View appLinks = mLayoutInflater
.inflate(R.layout.settings_entity_header, null /* root */);
when(mFragment.getActivity()).thenReturn(mock(Activity.class));
mController = EntityHeaderController.newInstance(mActivity, mFragment, appLinks);
mController.setPackageName("123")
.setUid(UserHandle.USER_SYSTEM)
.setButtonActions(
EntityHeaderController.ActionType.ACTION_APP_INFO,
EntityHeaderController.ActionType.ACTION_NOTIF_PREFERENCE);
mController.done(mActivity);
assertThat(appLinks.findViewById(android.R.id.button1).getVisibility())
.isEqualTo(View.VISIBLE);
assertThat(appLinks.findViewById(android.R.id.button2).getVisibility())
.isEqualTo(View.GONE);
}
@Test
public void bindButton_hasAppInfo_shouldHaveContentDescription() {
final View appLinks = mLayoutInflater
.inflate(R.layout.settings_entity_header, null /* root */);
when(mFragment.getActivity()).thenReturn(mock(Activity.class));
final Activity activity = mock(Activity.class);
when(mFragment.getActivity()).thenReturn(activity);
when(mContext.getString(eq(R.string.application_info_label))).thenReturn("App Info");
mController = EntityHeaderController.newInstance(mActivity, mFragment, appLinks);
mController.setPackageName("123")
.setUid(UserHandle.USER_SYSTEM)
.setHasAppInfoLink(true)
.setButtonActions(
EntityHeaderController.ActionType.ACTION_APP_INFO,
EntityHeaderController.ActionType.ACTION_NOTIF_PREFERENCE);
EntityHeaderController.ActionType.ACTION_NOTIF_PREFERENCE,
EntityHeaderController.ActionType.ACTION_NONE);
mController.done(mActivity);
assertThat(appLinks.findViewById(android.R.id.button1).getContentDescription().toString())
.isEqualTo("App info");
appLinks.findViewById(R.id.entity_header_content).performClick();
verify(activity).startActivityForResultAsUser(
any(Intent.class), anyInt(), any(UserHandle.class));
}
@Test