diff --git a/src/com/android/settings/homepage/SettingsHomepageActivity.java b/src/com/android/settings/homepage/SettingsHomepageActivity.java index 183a2fbf5f5..4726059455e 100644 --- a/src/com/android/settings/homepage/SettingsHomepageActivity.java +++ b/src/com/android/settings/homepage/SettingsHomepageActivity.java @@ -25,6 +25,8 @@ import android.app.ActivityManager; import android.app.settings.SettingsEnums; import android.content.ComponentName; import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; import android.content.res.Configuration; import android.os.Bundle; import android.text.TextUtils; @@ -38,6 +40,7 @@ import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.Toolbar; +import androidx.annotation.VisibleForTesting; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; @@ -55,6 +58,7 @@ import com.android.settings.core.CategoryMixin; import com.android.settings.core.FeatureFlags; import com.android.settings.homepage.contextualcards.ContextualCardsFragment; import com.android.settings.overlay.FeatureFactory; +import com.android.settings.password.PasswordUtils; import com.android.settingslib.Utils; import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin; @@ -351,6 +355,32 @@ public class SettingsHomepageActivity extends FragmentActivity implements finish(); return; } + + if (!TextUtils.equals(PasswordUtils.getCallingAppPackageName(getActivityToken()), + getPackageName())) { + ActivityInfo targetActivityInfo = null; + try { + targetActivityInfo = getPackageManager().getActivityInfo(targetComponentName, + /* flags= */ 0); + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "Failed to get target ActivityInfo: " + e); + finish(); + return; + } + + if (!targetActivityInfo.exported) { + Log.e(TAG, "Must not launch an unexported Actvity for deep link"); + finish(); + return; + } + + if (!isCallingAppPermitted(targetActivityInfo.permission)) { + Log.e(TAG, "Calling app must have the permission of deep link Activity"); + finish(); + return; + } + } + targetIntent.setComponent(targetComponentName); // To prevent launchDeepLinkIntentToRight again for configuration change. @@ -386,6 +416,12 @@ public class SettingsHomepageActivity extends FragmentActivity implements startActivity(targetIntent); } + @VisibleForTesting + boolean isCallingAppPermitted(String permission) { + return TextUtils.isEmpty(permission) || PasswordUtils.isCallingAppPermitted( + this, getActivityToken(), permission); + } + private String getHighlightMenuKey() { final Intent intent = getIntent(); if (intent != null && TextUtils.equals(intent.getAction(), diff --git a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java index 4d203a8a6b0..4de8b005c3c 100644 --- a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java +++ b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java @@ -20,6 +20,8 @@ import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTE import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; @@ -37,9 +39,11 @@ import androidx.fragment.app.Fragment; import com.android.settings.R; import com.android.settings.dashboard.suggestions.SuggestionFeatureProviderImpl; import com.android.settings.homepage.contextualcards.slices.BatteryFixSliceTest; +import com.android.settings.testutils.shadow.ShadowPasswordUtils; import com.android.settings.testutils.shadow.ShadowUserManager; import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -66,6 +70,11 @@ public class SettingsHomepageActivityTest { MockitoAnnotations.initMocks(this); } + @After + public void tearDown() { + ShadowPasswordUtils.reset(); + } + @Test public void launch_shouldHaveAnimationForIaFragment() { final SettingsHomepageActivity activity = Robolectric.buildActivity( @@ -195,6 +204,32 @@ public class SettingsHomepageActivityTest { & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS).isEqualTo(0); } + @Test + @Config(shadows = {ShadowPasswordUtils.class}) + public void isCallingAppPermitted_emptyPermission_returnTrue() { + SettingsHomepageActivity homepageActivity = spy(new SettingsHomepageActivity()); + + assertTrue(homepageActivity.isCallingAppPermitted("")); + } + + @Test + @Config(shadows = {ShadowPasswordUtils.class}) + public void isCallingAppPermitted_noGrantedPermission_returnFalse() { + SettingsHomepageActivity homepageActivity = spy(new SettingsHomepageActivity()); + + assertFalse(homepageActivity.isCallingAppPermitted("android.permission.TEST")); + } + + @Test + @Config(shadows = {ShadowPasswordUtils.class}) + public void isCallingAppPermitted_grantedPermission_returnTrue() { + SettingsHomepageActivity homepageActivity = spy(new SettingsHomepageActivity()); + String permission = "android.permission.TEST"; + ShadowPasswordUtils.addGrantedPermission(permission); + + assertTrue(homepageActivity.isCallingAppPermitted(permission)); + } + @Implements(SuggestionFeatureProviderImpl.class) public static class ShadowSuggestionFeatureProviderImpl {