Merge "Mitigate Intent Capturing vulnerability"
This commit is contained in:
committed by
Android (Google) Code Review
commit
4808660569
@@ -101,6 +101,7 @@ public class ResolverActivity extends Activity {
|
||||
private AbsListView mAdapterView;
|
||||
private Button mAlwaysButton;
|
||||
private Button mOnceButton;
|
||||
private Button mSettingsButton;
|
||||
private View mProfileView;
|
||||
private int mIconDpi;
|
||||
private int mLastSelected = AbsListView.INVALID_POSITION;
|
||||
@@ -112,6 +113,7 @@ public class ResolverActivity extends Activity {
|
||||
private String mReferrerPackage;
|
||||
private CharSequence mTitle;
|
||||
private int mDefaultTitleResId;
|
||||
private boolean mUseLayoutForBrowsables;
|
||||
|
||||
// Whether or not this activity supports choosing a default handler for the intent.
|
||||
private boolean mSupportsAlwaysUseOption;
|
||||
@@ -192,6 +194,12 @@ public class ResolverActivity extends Activity {
|
||||
com.android.internal.R.string.whichHomeApplicationNamed,
|
||||
com.android.internal.R.string.whichHomeApplicationLabel);
|
||||
|
||||
// SpR.id.buttonecial titles for BROWSABLE components
|
||||
public static final int BROWSABLE_TITLE_RES =
|
||||
com.android.internal.R.string.whichGiveAccessToApplication;
|
||||
public static final int BROWSABLE_NAMED_TITLE_RES =
|
||||
com.android.internal.R.string.whichGiveAccessToApplicationNamed;
|
||||
|
||||
public final String action;
|
||||
public final int titleRes;
|
||||
public final int namedTitleRes;
|
||||
@@ -283,7 +291,6 @@ public class ResolverActivity extends Activity {
|
||||
mPackageMonitor.register(this, getMainLooper(), false);
|
||||
mRegistered = true;
|
||||
mReferrerPackage = getReferrerPackageName();
|
||||
mSupportsAlwaysUseOption = supportsAlwaysUseOption;
|
||||
|
||||
final ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
|
||||
mIconDpi = am.getLauncherLargeIconDensity();
|
||||
@@ -293,6 +300,14 @@ public class ResolverActivity extends Activity {
|
||||
mTitle = title;
|
||||
mDefaultTitleResId = defaultTitleRes;
|
||||
|
||||
mUseLayoutForBrowsables = getTargetIntent() == null
|
||||
? false
|
||||
: getTargetIntent().hasCategory(Intent.CATEGORY_BROWSABLE);
|
||||
|
||||
// We don't want to support Always Use if browsable layout is being used,
|
||||
// as to mitigate Intent Capturing vulnerability
|
||||
mSupportsAlwaysUseOption = supportsAlwaysUseOption && !mUseLayoutForBrowsables;
|
||||
|
||||
mIconFactory = IconDrawableFactory.newInstance(this, true);
|
||||
if (configureContentView(mIntents, initialIntents, rList)) {
|
||||
return;
|
||||
@@ -448,13 +463,23 @@ public class ResolverActivity extends Activity {
|
||||
mSafeForwardingMode = safeForwarding;
|
||||
}
|
||||
|
||||
protected CharSequence getTitleForAction(String action, int defaultTitleRes) {
|
||||
final ActionTitle title = mResolvingHome ? ActionTitle.HOME : ActionTitle.forAction(action);
|
||||
protected CharSequence getTitleForAction(Intent intent, int defaultTitleRes) {
|
||||
final ActionTitle title = mResolvingHome
|
||||
? ActionTitle.HOME
|
||||
: ActionTitle.forAction(intent.getAction());
|
||||
|
||||
// While there may already be a filtered item, we can only use it in the title if the list
|
||||
// is already sorted and all information relevant to it is already in the list.
|
||||
final boolean named = mAdapter.getFilteredPosition() >= 0;
|
||||
if (title == ActionTitle.DEFAULT && defaultTitleRes != 0) {
|
||||
return getString(defaultTitleRes);
|
||||
} else if (intent.hasCategory(Intent.CATEGORY_BROWSABLE)) {
|
||||
// If the Intent is BROWSABLE then we need to warn the user that
|
||||
// they're giving access for the activity to open URLs from this specific host
|
||||
return named
|
||||
? getString(ActionTitle.BROWSABLE_NAMED_TITLE_RES, intent.getData().getHost(),
|
||||
mAdapter.getFilteredItem().getDisplayLabel())
|
||||
: getString(ActionTitle.BROWSABLE_TITLE_RES, intent.getData().getHost());
|
||||
} else {
|
||||
return named
|
||||
? getString(title.namedTitleRes, mAdapter.getFilteredItem().getDisplayLabel())
|
||||
@@ -555,7 +580,7 @@ public class ResolverActivity extends Activity {
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Bundle savedInstanceState) {
|
||||
super.onRestoreInstanceState(savedInstanceState);
|
||||
resetAlwaysOrOnceButtonBar();
|
||||
resetButtonBar();
|
||||
}
|
||||
|
||||
private boolean hasManagedProfile() {
|
||||
@@ -607,11 +632,23 @@ public class ResolverActivity extends Activity {
|
||||
|
||||
public void onButtonClick(View v) {
|
||||
final int id = v.getId();
|
||||
startSelected(mAdapter.hasFilteredItem() ?
|
||||
mAdapter.getFilteredPosition():
|
||||
mAdapterView.getCheckedItemPosition(),
|
||||
id == R.id.button_always,
|
||||
!mAdapter.hasFilteredItem());
|
||||
int which = mAdapter.hasFilteredItem()
|
||||
? mAdapter.getFilteredPosition()
|
||||
: mAdapterView.getCheckedItemPosition();
|
||||
boolean hasIndexBeenFiltered = !mAdapter.hasFilteredItem();
|
||||
if (id == R.id.button_app_settings) {
|
||||
showSettingsForSelected(which, hasIndexBeenFiltered);
|
||||
} else {
|
||||
startSelected(which, id == R.id.button_always, hasIndexBeenFiltered);
|
||||
}
|
||||
}
|
||||
|
||||
private void showSettingsForSelected(int which, boolean hasIndexBeenFiltered) {
|
||||
ResolveInfo ri = mAdapter.resolveInfoForPosition(which, hasIndexBeenFiltered);
|
||||
Intent in = new Intent().setAction(Settings.ACTION_APP_OPEN_BY_DEFAULT_SETTINGS)
|
||||
.setData(Uri.fromParts("package", ri.activityInfo.packageName, null))
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
|
||||
startActivity(in);
|
||||
}
|
||||
|
||||
public void startSelected(int which, boolean always, boolean hasIndexBeenFiltered) {
|
||||
@@ -995,7 +1032,7 @@ public class ResolverActivity extends Activity {
|
||||
adapterView.setOnItemClickListener(listener);
|
||||
adapterView.setOnItemLongClickListener(listener);
|
||||
|
||||
if (mSupportsAlwaysUseOption) {
|
||||
if (mSupportsAlwaysUseOption || mUseLayoutForBrowsables) {
|
||||
listView.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE);
|
||||
}
|
||||
|
||||
@@ -1017,7 +1054,7 @@ public class ResolverActivity extends Activity {
|
||||
|
||||
CharSequence title = mTitle != null
|
||||
? mTitle
|
||||
: getTitleForAction(getTargetIntent().getAction(), mDefaultTitleResId);
|
||||
: getTitleForAction(getTargetIntent(), mDefaultTitleResId);
|
||||
|
||||
if (!TextUtils.isEmpty(title)) {
|
||||
final TextView titleView = findViewById(R.id.title);
|
||||
@@ -1051,16 +1088,47 @@ public class ResolverActivity extends Activity {
|
||||
}
|
||||
}
|
||||
|
||||
public void resetAlwaysOrOnceButtonBar() {
|
||||
if (mSupportsAlwaysUseOption) {
|
||||
final ViewGroup buttonLayout = findViewById(R.id.button_bar);
|
||||
if (buttonLayout != null) {
|
||||
buttonLayout.setVisibility(View.VISIBLE);
|
||||
mAlwaysButton = (Button) buttonLayout.findViewById(R.id.button_always);
|
||||
mOnceButton = (Button) buttonLayout.findViewById(R.id.button_once);
|
||||
private void resetButtonBar() {
|
||||
if (!mSupportsAlwaysUseOption && !mUseLayoutForBrowsables) {
|
||||
return;
|
||||
}
|
||||
final ViewGroup buttonLayout = findViewById(R.id.button_bar);
|
||||
if (buttonLayout != null) {
|
||||
buttonLayout.setVisibility(View.VISIBLE);
|
||||
mOnceButton = (Button) buttonLayout.findViewById(R.id.button_once);
|
||||
mSettingsButton = (Button) buttonLayout.findViewById(R.id.button_app_settings);
|
||||
mAlwaysButton = (Button) buttonLayout.findViewById(R.id.button_always);
|
||||
|
||||
if (mUseLayoutForBrowsables) {
|
||||
resetSettingsOrOnceButtonBar();
|
||||
} else {
|
||||
Log.e(TAG, "Layout unexpectedly does not have a button bar");
|
||||
resetAlwaysOrOnceButtonBar();
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "Layout unexpectedly does not have a button bar");
|
||||
}
|
||||
}
|
||||
|
||||
private void resetSettingsOrOnceButtonBar() {
|
||||
//unsetting always button
|
||||
mAlwaysButton.setVisibility(View.GONE);
|
||||
|
||||
// When the items load in, if an item was already selected,
|
||||
// enable the buttons
|
||||
if (mAdapterView != null
|
||||
&& mAdapterView.getCheckedItemPosition() != ListView.INVALID_POSITION) {
|
||||
mSettingsButton.setEnabled(true);
|
||||
mOnceButton.setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void resetAlwaysOrOnceButtonBar() {
|
||||
// This check needs to be made because layout with default
|
||||
// doesn't have a settings button
|
||||
if (mSettingsButton != null) {
|
||||
//unsetting always button
|
||||
mSettingsButton.setVisibility(View.GONE);
|
||||
mSettingsButton = null;
|
||||
}
|
||||
|
||||
if (useLayoutWithDefault()
|
||||
@@ -1625,7 +1693,7 @@ public class ResolverActivity extends Activity {
|
||||
@Override
|
||||
public void run() {
|
||||
setTitleAndIcon();
|
||||
resetAlwaysOrOnceButtonBar();
|
||||
resetButtonBar();
|
||||
onListRebuilt();
|
||||
mPostListReadyRunnable = null;
|
||||
}
|
||||
@@ -1986,8 +2054,14 @@ public class ResolverActivity extends Activity {
|
||||
final boolean hasValidSelection = checkedPos != ListView.INVALID_POSITION;
|
||||
if (!useLayoutWithDefault()
|
||||
&& (!hasValidSelection || mLastSelected != checkedPos)
|
||||
&& mAlwaysButton != null) {
|
||||
setAlwaysButtonEnabled(hasValidSelection, checkedPos, true);
|
||||
&& (mAlwaysButton != null || mSettingsButton != null)) {
|
||||
if (mSettingsButton != null) {
|
||||
// this implies that the layout for browsables is being used
|
||||
mSettingsButton.setEnabled(true);
|
||||
} else {
|
||||
// this implies that mAlwaysButton != null
|
||||
setAlwaysButtonEnabled(hasValidSelection, checkedPos, true);
|
||||
}
|
||||
mOnceButton.setEnabled(hasValidSelection);
|
||||
if (hasValidSelection) {
|
||||
mAdapterView.smoothScrollToPosition(checkedPos);
|
||||
|
||||
@@ -129,6 +129,18 @@
|
||||
android:enabled="false"
|
||||
android:text="@string/activity_resolver_use_always"
|
||||
android:onClick="onButtonClick" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_app_settings"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:maxLines="2"
|
||||
android:minHeight="@dimen/alert_dialog_button_bar_height"
|
||||
style="?attr/buttonBarPositiveButtonStyle"
|
||||
android:layout_height="wrap_content"
|
||||
android:enabled="false"
|
||||
android:text="@string/activity_resolver_app_settings"
|
||||
android:onClick="onButtonClick" />
|
||||
</LinearLayout>
|
||||
|
||||
</com.android.internal.widget.ResolverDrawerLayout>
|
||||
|
||||
@@ -3066,6 +3066,14 @@
|
||||
<string name="whichViewApplicationNamed">Open with %1$s</string>
|
||||
<!-- Label for a link to a intent resolver dialog to view something -->
|
||||
<string name="whichViewApplicationLabel">Open</string>
|
||||
<!-- Title of intent resolver dialog when selecting a viewer application that opens URI
|
||||
[CHAR LIMIT=128]. -->
|
||||
<string name="whichGiveAccessToApplication">Give access to open <xliff:g id="host" example="mail.google.com">%1$s</xliff:g> links with</string>
|
||||
<!-- Title of intent resolver dialog when selecting a viewer application that opens URI
|
||||
and a previously used application is known [CHAR LIMIT=128]. -->
|
||||
<string name="whichGiveAccessToApplicationNamed">Give access to open <xliff:g id="host" example="mail.google.com">%1$s</xliff:g> links with <xliff:g id="application" example="Gmail">%2$s</xliff:g></string>
|
||||
<!-- Label for a link to an intent resolver dialog to open URI [CHAR LIMIT=16] -->
|
||||
<string name="whichGiveAccessToApplicationLabel">Give access</string>
|
||||
<!-- Title of intent resolver dialog when selecting an editor application to run. -->
|
||||
<string name="whichEditApplication">Edit with</string>
|
||||
<!-- Title of intent resolver dialog when selecting an editor application to run
|
||||
@@ -4156,6 +4164,10 @@
|
||||
from the activity resolver to use just this once. [CHAR LIMIT=25] -->
|
||||
<string name="activity_resolver_use_once">Just once</string>
|
||||
|
||||
<!-- Title for a button to choose to go to
|
||||
'Open by Default' app settings. [CHAR LIMIT=25] -->
|
||||
<string name="activity_resolver_app_settings">Settings</string>
|
||||
|
||||
<!-- Text for the toast that is shown when the user clicks on a launcher that
|
||||
doesn't support the work profile. [CHAR LIMIT=100] -->
|
||||
<string name="activity_resolver_work_profiles_support">%1$s doesn\'t support work profile</string>
|
||||
|
||||
@@ -2144,6 +2144,7 @@
|
||||
<java-symbol type="id" name="resolver_list" />
|
||||
<java-symbol type="id" name="button_once" />
|
||||
<java-symbol type="id" name="button_always" />
|
||||
<java-symbol type="id" name="button_app_settings" />
|
||||
<java-symbol type="integer" name="config_globalActionsKeyTimeout" />
|
||||
<java-symbol type="integer" name="config_maxResolverActivityColumns" />
|
||||
<java-symbol type="array" name="config_notificationSignalExtractors" />
|
||||
@@ -2499,11 +2500,15 @@
|
||||
<java-symbol type="bool" name="config_use_voip_mode_for_ims" />
|
||||
<java-symbol type="attr" name="touchscreenBlocksFocus" />
|
||||
<java-symbol type="layout" name="resolver_list_with_default" />
|
||||
<java-symbol type="string" name="activity_resolver_app_settings" />
|
||||
<java-symbol type="string" name="whichApplicationNamed" />
|
||||
<java-symbol type="string" name="whichApplicationLabel" />
|
||||
<java-symbol type="string" name="whichViewApplication" />
|
||||
<java-symbol type="string" name="whichViewApplicationNamed" />
|
||||
<java-symbol type="string" name="whichViewApplicationLabel" />
|
||||
<java-symbol type="string" name="whichGiveAccessToApplication" />
|
||||
<java-symbol type="string" name="whichGiveAccessToApplicationNamed" />
|
||||
<java-symbol type="string" name="whichGiveAccessToApplicationLabel" />
|
||||
<java-symbol type="string" name="whichEditApplication" />
|
||||
<java-symbol type="string" name="whichEditApplicationNamed" />
|
||||
<java-symbol type="string" name="whichEditApplicationLabel" />
|
||||
|
||||
Reference in New Issue
Block a user