Loading AndroidManifest.xml +8 −0 Original line number Diff line number Diff line Loading @@ -88,6 +88,14 @@ android:theme="@style/DocumentsTheme"> </activity> <activity android:name=".ForResultForwarderActivity" android:theme="@android:style/Theme.NoDisplay" android:excludeFromRecents="true" android:finishOnCloseSystemDialogs="true" android:exported="false"> </activity> <!-- Preserve original launcher activity from Nougat. --> <activity-alias android:name=".LauncherActivity" Loading src/com/android/documentsui/ForResultForwarderActivity.java 0 → 100644 +69 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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.documentsui; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.util.Log; import com.android.documentsui.base.UserId; /** * Forwards a cross-profile startActivityForResult intent. */ public class ForResultForwarderActivity extends Activity { private static final String TAG = "ForResultForwarderActiv"; private static final String EXTRA_INTENT = "EXTRA_INTENT"; private static final String EXTRA_USER = "EXTRA_USER"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); final Intent intent = getIntent(); if (!intent.hasExtra(EXTRA_INTENT) || !intent.hasExtra(EXTRA_USER)) { Log.e(TAG, "Missing intent or user"); setResult(Activity.RESULT_CANCELED); finish(); return; } Intent targetIntent = intent.getParcelableExtra(EXTRA_INTENT); // We should never have the default value because of the above check UserId targetUserId = UserId.of(intent.getIntExtra(EXTRA_USER, /* defaultValue= */ -1)); targetIntent.addFlags( Intent.FLAG_ACTIVITY_FORWARD_RESULT | Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP); try { targetUserId.startActivityAsUser(this, targetIntent); } catch (RuntimeException e) { Log.e(TAG, "Failed to forward activity"); setResult(Activity.RESULT_CANCELED); } finish(); } public static Intent getIntent(Context context, Intent intent, UserId targetUserId) { Intent forwarder = new Intent(context, ForResultForwarderActivity.class); forwarder.putExtra(EXTRA_INTENT, intent); forwarder.putExtra(EXTRA_USER, targetUserId.getIdentifier()); return forwarder; } } src/com/android/documentsui/picker/ActionHandler.java +5 −1 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ import androidx.recyclerview.selection.ItemDetailsLookup.ItemDetails; import com.android.documentsui.AbstractActionHandler; import com.android.documentsui.ActivityConfig; import com.android.documentsui.DocumentsAccess; import com.android.documentsui.ForResultForwarderActivity; import com.android.documentsui.Injector; import com.android.documentsui.MetricConsts; import com.android.documentsui.Metrics; Loading Loading @@ -313,7 +314,7 @@ class ActionHandler<T extends FragmentActivity & Addons> extends AbstractActionH return; } final Intent intent = new Intent(mActivity.getIntent()); Intent intent = new Intent(mActivity.getIntent()); final int flagsRemoved = Intent.FLAG_ACTIVITY_FORWARD_RESULT | Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION Loading @@ -322,6 +323,9 @@ class ActionHandler<T extends FragmentActivity & Addons> extends AbstractActionH intent.setFlags(intent.getFlags() & ~flagsRemoved); intent.setComponent(new ComponentName( info.activityInfo.applicationInfo.packageName, info.activityInfo.name)); if (!UserId.CURRENT_USER.equals(userId)) { intent = ForResultForwarderActivity.getIntent(mActivity, intent, userId); } try { boolean isCurrentUser = UserId.CURRENT_USER.equals(userId); mActivity.startActivityForResult(intent, Loading tests/AndroidManifest.xml +8 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,14 @@ </intent-filter> </activity> <activity android:name="com.android.documentsui.PickActivityTest$ReturnResultActivity"> <intent-filter> <action android:name="com.android.documentsui.test.action.RETURN_RESULT" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> <provider android:name="com.android.documentsui.StubProvider" android:authorities="com.android.documentsui.stubprovider" Loading tests/unit/com/android/documentsui/ForResultForwarderActivityTest.java 0 → 100644 +55 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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.documentsui; import static com.google.common.truth.Truth.assertThat; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ResolveInfo; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; import com.android.documentsui.testing.TestProvidersAccess; import org.junit.Before; import org.junit.Test; @SmallTest public class ForResultForwarderActivityTest { private Context mTargetContext; @Before public void setUp() throws Exception { mTargetContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); } @Test public void testActivityNotExported() { Intent originalIntent = new Intent("some_action"); Intent intent = ForResultForwarderActivity.getIntent(mTargetContext, originalIntent, TestProvidersAccess.USER_ID); ResolveInfo info = mTargetContext.getPackageManager().resolveActivity(intent, 0); assertThat(info.activityInfo.getComponentName()) .isEqualTo(new ComponentName(mTargetContext, ForResultForwarderActivity.class)); assertThat(info.activityInfo.exported).isFalse(); } } Loading
AndroidManifest.xml +8 −0 Original line number Diff line number Diff line Loading @@ -88,6 +88,14 @@ android:theme="@style/DocumentsTheme"> </activity> <activity android:name=".ForResultForwarderActivity" android:theme="@android:style/Theme.NoDisplay" android:excludeFromRecents="true" android:finishOnCloseSystemDialogs="true" android:exported="false"> </activity> <!-- Preserve original launcher activity from Nougat. --> <activity-alias android:name=".LauncherActivity" Loading
src/com/android/documentsui/ForResultForwarderActivity.java 0 → 100644 +69 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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.documentsui; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.util.Log; import com.android.documentsui.base.UserId; /** * Forwards a cross-profile startActivityForResult intent. */ public class ForResultForwarderActivity extends Activity { private static final String TAG = "ForResultForwarderActiv"; private static final String EXTRA_INTENT = "EXTRA_INTENT"; private static final String EXTRA_USER = "EXTRA_USER"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); final Intent intent = getIntent(); if (!intent.hasExtra(EXTRA_INTENT) || !intent.hasExtra(EXTRA_USER)) { Log.e(TAG, "Missing intent or user"); setResult(Activity.RESULT_CANCELED); finish(); return; } Intent targetIntent = intent.getParcelableExtra(EXTRA_INTENT); // We should never have the default value because of the above check UserId targetUserId = UserId.of(intent.getIntExtra(EXTRA_USER, /* defaultValue= */ -1)); targetIntent.addFlags( Intent.FLAG_ACTIVITY_FORWARD_RESULT | Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP); try { targetUserId.startActivityAsUser(this, targetIntent); } catch (RuntimeException e) { Log.e(TAG, "Failed to forward activity"); setResult(Activity.RESULT_CANCELED); } finish(); } public static Intent getIntent(Context context, Intent intent, UserId targetUserId) { Intent forwarder = new Intent(context, ForResultForwarderActivity.class); forwarder.putExtra(EXTRA_INTENT, intent); forwarder.putExtra(EXTRA_USER, targetUserId.getIdentifier()); return forwarder; } }
src/com/android/documentsui/picker/ActionHandler.java +5 −1 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ import androidx.recyclerview.selection.ItemDetailsLookup.ItemDetails; import com.android.documentsui.AbstractActionHandler; import com.android.documentsui.ActivityConfig; import com.android.documentsui.DocumentsAccess; import com.android.documentsui.ForResultForwarderActivity; import com.android.documentsui.Injector; import com.android.documentsui.MetricConsts; import com.android.documentsui.Metrics; Loading Loading @@ -313,7 +314,7 @@ class ActionHandler<T extends FragmentActivity & Addons> extends AbstractActionH return; } final Intent intent = new Intent(mActivity.getIntent()); Intent intent = new Intent(mActivity.getIntent()); final int flagsRemoved = Intent.FLAG_ACTIVITY_FORWARD_RESULT | Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION Loading @@ -322,6 +323,9 @@ class ActionHandler<T extends FragmentActivity & Addons> extends AbstractActionH intent.setFlags(intent.getFlags() & ~flagsRemoved); intent.setComponent(new ComponentName( info.activityInfo.applicationInfo.packageName, info.activityInfo.name)); if (!UserId.CURRENT_USER.equals(userId)) { intent = ForResultForwarderActivity.getIntent(mActivity, intent, userId); } try { boolean isCurrentUser = UserId.CURRENT_USER.equals(userId); mActivity.startActivityForResult(intent, Loading
tests/AndroidManifest.xml +8 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,14 @@ </intent-filter> </activity> <activity android:name="com.android.documentsui.PickActivityTest$ReturnResultActivity"> <intent-filter> <action android:name="com.android.documentsui.test.action.RETURN_RESULT" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> <provider android:name="com.android.documentsui.StubProvider" android:authorities="com.android.documentsui.stubprovider" Loading
tests/unit/com/android/documentsui/ForResultForwarderActivityTest.java 0 → 100644 +55 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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.documentsui; import static com.google.common.truth.Truth.assertThat; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ResolveInfo; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; import com.android.documentsui.testing.TestProvidersAccess; import org.junit.Before; import org.junit.Test; @SmallTest public class ForResultForwarderActivityTest { private Context mTargetContext; @Before public void setUp() throws Exception { mTargetContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); } @Test public void testActivityNotExported() { Intent originalIntent = new Intent("some_action"); Intent intent = ForResultForwarderActivity.getIntent(mTargetContext, originalIntent, TestProvidersAccess.USER_ID); ResolveInfo info = mTargetContext.getPackageManager().resolveActivity(intent, 0); assertThat(info.activityInfo.getComponentName()) .isEqualTo(new ComponentName(mTargetContext, ForResultForwarderActivity.class)); assertThat(info.activityInfo.exported).isFalse(); } }