[Partial screen sharing] App selector initial version
Adds an activity that inherits ChooserActivity to select an app in the partial screen sharing flow under a feature flag. It doesn't have a proper visual design, analytics, enterprise policies handling. Bug: 218314434 Test: start partial screen sharing Change-Id: Ia7d9ae07e2ef35d33f85530f26cab4e6cdc1f94a
This commit is contained in:
@@ -265,6 +265,7 @@ public class ResolverListAdapter extends BaseAdapter {
|
||||
return mResolverListController.getResolversForIntent(
|
||||
/* shouldGetResolvedFilter= */ true,
|
||||
mResolverListCommunicator.shouldGetActivityMetadata(),
|
||||
mResolverListCommunicator.shouldGetOnlyDefaultActivities(),
|
||||
mIntents);
|
||||
}
|
||||
}
|
||||
@@ -727,6 +728,7 @@ public class ResolverListAdapter extends BaseAdapter {
|
||||
protected List<ResolvedComponentInfo> getResolversForUser(UserHandle userHandle) {
|
||||
return mResolverListController.getResolversForIntentAsUser(true,
|
||||
mResolverListCommunicator.shouldGetActivityMetadata(),
|
||||
mResolverListCommunicator.shouldGetOnlyDefaultActivities(),
|
||||
mIntents, userHandle);
|
||||
}
|
||||
|
||||
@@ -820,6 +822,12 @@ public class ResolverListAdapter extends BaseAdapter {
|
||||
|
||||
boolean shouldGetActivityMetadata();
|
||||
|
||||
/**
|
||||
* @return true to filter only apps that can handle
|
||||
* {@link android.content.Intent#CATEGORY_DEFAULT} intents
|
||||
*/
|
||||
default boolean shouldGetOnlyDefaultActivities() { return true; };
|
||||
|
||||
Intent getTargetIntent();
|
||||
|
||||
void onHandlePackagesChanged(ResolverListAdapter listAdapter);
|
||||
|
||||
@@ -110,17 +110,19 @@ public class ResolverListController {
|
||||
public List<ResolverActivity.ResolvedComponentInfo> getResolversForIntent(
|
||||
boolean shouldGetResolvedFilter,
|
||||
boolean shouldGetActivityMetadata,
|
||||
boolean shouldGetOnlyDefaultActivities,
|
||||
List<Intent> intents) {
|
||||
return getResolversForIntentAsUser(shouldGetResolvedFilter, shouldGetActivityMetadata,
|
||||
intents, mUserHandle);
|
||||
shouldGetOnlyDefaultActivities, intents, mUserHandle);
|
||||
}
|
||||
|
||||
public List<ResolverActivity.ResolvedComponentInfo> getResolversForIntentAsUser(
|
||||
boolean shouldGetResolvedFilter,
|
||||
boolean shouldGetActivityMetadata,
|
||||
boolean shouldGetOnlyDefaultActivities,
|
||||
List<Intent> intents,
|
||||
UserHandle userHandle) {
|
||||
int baseFlags = PackageManager.MATCH_DEFAULT_ONLY
|
||||
int baseFlags = (shouldGetOnlyDefaultActivities ? PackageManager.MATCH_DEFAULT_ONLY : 0)
|
||||
| PackageManager.MATCH_DIRECT_BOOT_AWARE
|
||||
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE
|
||||
| (shouldGetResolvedFilter ? PackageManager.GET_RESOLVED_FILTER : 0)
|
||||
|
||||
@@ -264,6 +264,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -287,6 +288,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -307,6 +309,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -327,6 +330,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -350,6 +354,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -376,6 +381,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -401,6 +407,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -422,6 +429,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -476,6 +484,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -516,6 +525,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -550,6 +560,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -585,6 +596,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -647,6 +659,7 @@ public class ChooserActivityTest {
|
||||
ResolveInfo toChoose = resolvedComponentInfos.get(1).getResolveInfoAt(0);
|
||||
|
||||
when(ChooserActivityOverrideData.getInstance().resolverListController.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
|
||||
@@ -686,6 +699,7 @@ public class ChooserActivityTest {
|
||||
ResolveInfo toChoose = resolvedComponentInfos.get(1).getResolveInfoAt(0);
|
||||
|
||||
when(ChooserActivityOverrideData.getInstance().resolverListController.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
|
||||
@@ -718,6 +732,7 @@ public class ChooserActivityTest {
|
||||
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
|
||||
|
||||
when(ChooserActivityOverrideData.getInstance().resolverListController.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
|
||||
@@ -745,6 +760,7 @@ public class ChooserActivityTest {
|
||||
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
|
||||
|
||||
when(ChooserActivityOverrideData.getInstance().resolverListController.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
|
||||
@@ -774,6 +790,7 @@ public class ChooserActivityTest {
|
||||
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
|
||||
|
||||
when(ChooserActivityOverrideData.getInstance().resolverListController.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
|
||||
@@ -844,6 +861,7 @@ public class ChooserActivityTest {
|
||||
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
|
||||
|
||||
when(ChooserActivityOverrideData.getInstance().resolverListController.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
|
||||
@@ -920,6 +938,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -956,6 +975,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -995,6 +1015,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -1089,6 +1110,7 @@ public class ChooserActivityTest {
|
||||
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
|
||||
|
||||
when(ChooserActivityOverrideData.getInstance().resolverListController.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
|
||||
@@ -1122,6 +1144,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -1155,6 +1178,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -1187,6 +1211,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -1216,6 +1241,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -1248,6 +1274,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -1282,6 +1309,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -1321,6 +1349,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -1363,6 +1392,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -1407,6 +1437,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -1483,6 +1514,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -1564,6 +1596,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -1636,6 +1669,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -1743,6 +1777,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -2058,6 +2093,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -2140,6 +2176,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -2227,6 +2264,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -2296,6 +2334,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -2444,6 +2483,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -2473,6 +2513,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -2526,6 +2567,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -2663,6 +2705,7 @@ public class ChooserActivityTest {
|
||||
createResolvedComponentsForTest(4);
|
||||
when(ChooserActivityOverrideData.getInstance().resolverListController.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
.thenReturn(new ArrayList<>(personalResolvedComponentInfos));
|
||||
@@ -3055,6 +3098,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -3064,6 +3108,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.workResolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
@@ -3073,6 +3118,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.workResolverListController
|
||||
.getResolversForIntentAsUser(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class),
|
||||
@@ -3129,6 +3175,7 @@ public class ChooserActivityTest {
|
||||
.getInstance()
|
||||
.resolverListController
|
||||
.getResolversForIntent(
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
|
||||
@@ -95,6 +95,7 @@ public class ResolverActivityTest {
|
||||
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
|
||||
|
||||
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
|
||||
|
||||
@@ -126,6 +127,7 @@ public class ResolverActivityTest {
|
||||
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
|
||||
|
||||
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
|
||||
waitForIdle();
|
||||
@@ -170,6 +172,7 @@ public class ResolverActivityTest {
|
||||
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
|
||||
|
||||
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
|
||||
waitForIdle();
|
||||
@@ -202,6 +205,7 @@ public class ResolverActivityTest {
|
||||
ResolveInfo toChoose = resolvedComponentInfos.get(0).getResolveInfoAt(0);
|
||||
|
||||
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
|
||||
when(sOverrides.resolverListController.getLastChosen())
|
||||
@@ -272,6 +276,7 @@ public class ResolverActivityTest {
|
||||
ResolveInfo toChoose = resolvedComponentInfos.get(1).getResolveInfoAt(0);
|
||||
|
||||
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
|
||||
|
||||
@@ -316,6 +321,7 @@ public class ResolverActivityTest {
|
||||
ResolveInfo toChoose = resolvedComponentInfos.get(1).getResolveInfoAt(0);
|
||||
|
||||
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
|
||||
when(sOverrides.resolverListController.getLastChosen())
|
||||
@@ -806,6 +812,7 @@ public class ResolverActivityTest {
|
||||
List<ResolvedComponentInfo> personalResolvedComponentInfos =
|
||||
createResolvedComponentsForTestWithOtherProfile(2, /* userId */ 10);
|
||||
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
.thenReturn(new ArrayList<>(personalResolvedComponentInfos));
|
||||
@@ -830,6 +837,7 @@ public class ResolverActivityTest {
|
||||
List<ResolvedComponentInfo> personalResolvedComponentInfos =
|
||||
createResolvedComponentsForTest(1);
|
||||
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
.thenReturn(new ArrayList<>(personalResolvedComponentInfos));
|
||||
@@ -887,6 +895,7 @@ public class ResolverActivityTest {
|
||||
createResolvedComponentsForTest(2);
|
||||
|
||||
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
|
||||
when(sOverrides.resolverListController.getLastChosen())
|
||||
@@ -964,13 +973,16 @@ public class ResolverActivityTest {
|
||||
List<ResolvedComponentInfo> personalResolvedComponentInfos,
|
||||
List<ResolvedComponentInfo> workResolvedComponentInfos) {
|
||||
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class)))
|
||||
.thenReturn(new ArrayList<>(personalResolvedComponentInfos));
|
||||
when(sOverrides.workResolverListController.getResolversForIntent(Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class))).thenReturn(workResolvedComponentInfos);
|
||||
when(sOverrides.workResolverListController.getResolversForIntentAsUser(Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.anyBoolean(),
|
||||
Mockito.isA(List.class),
|
||||
eq(UserHandle.SYSTEM)))
|
||||
|
||||
@@ -20,11 +20,14 @@ import static junit.framework.Assert.assertEquals;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.mockito.ArgumentMatchers.intThat;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Matchers.anyLong;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.usage.IUsageStatsManager;
|
||||
@@ -48,6 +51,7 @@ import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentMatcher;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
@@ -78,6 +82,8 @@ public class ResolverListControllerTest {
|
||||
Configuration config = new Configuration();
|
||||
config.locale = Locale.getDefault();
|
||||
List<ResolveInfo> services = new ArrayList<>();
|
||||
mUsm = new UsageStatsManager(mMockContext, mMockService);
|
||||
when(mMockContext.getSystemService(Context.USAGE_STATS_SERVICE)).thenReturn(mUsm);
|
||||
when(mMockPackageManager.queryIntentServices(any(), anyInt())).thenReturn(services);
|
||||
when(mMockResources.getConfiguration()).thenReturn(config);
|
||||
when(mMockContext.getResources()).thenReturn(mMockResources);
|
||||
@@ -112,8 +118,6 @@ public class ResolverListControllerTest {
|
||||
doAnswer(answer).when(mMockService).reportChooserSelection(
|
||||
anyString(), anyInt(), anyString(), any(), anyString());
|
||||
when(mMockContext.getOpPackageName()).thenReturn(refererPackage);
|
||||
mUsm = new UsageStatsManager(mMockContext, mMockService);
|
||||
when(mMockContext.getSystemService(Context.USAGE_STATS_SERVICE)).thenReturn(mUsm);
|
||||
mController = new ResolverListController(mMockContext, mMockPackageManager, sendIntent,
|
||||
refererPackage, UserHandle.USER_CURRENT, /* userHandle */ UserHandle.SYSTEM);
|
||||
mController.sort(new ArrayList<ResolvedComponentInfo>());
|
||||
@@ -129,8 +133,6 @@ public class ResolverListControllerTest {
|
||||
Intent sendIntent = createSendImageIntent(annotation);
|
||||
String refererPackage = "test_referer_package";
|
||||
List<ResolvedComponentInfo> resolvedComponents = createResolvedComponentsForTest(10);
|
||||
mUsm = new UsageStatsManager(mMockContext, mMockService);
|
||||
when(mMockContext.getSystemService(Context.USAGE_STATS_SERVICE)).thenReturn(mUsm);
|
||||
mController = new ResolverListController(mMockContext, mMockPackageManager, sendIntent,
|
||||
refererPackage, UserHandle.USER_CURRENT, /* userHandle */ UserHandle.SYSTEM);
|
||||
List<ResolvedComponentInfo> topKList = new ArrayList<>(resolvedComponents);
|
||||
@@ -151,6 +153,102 @@ public class ResolverListControllerTest {
|
||||
sortList, topKList);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getResolversForIntent_usesResultsFromPackageManager() {
|
||||
mockStats();
|
||||
List<ResolveInfo> infos = new ArrayList<>();
|
||||
infos.add(ResolverDataProvider.createResolveInfo(0, UserHandle.USER_CURRENT));
|
||||
when(mMockPackageManager.queryIntentActivitiesAsUser(any(), anyInt(),
|
||||
any(UserHandle.class))).thenReturn(infos);
|
||||
mController = new ResolverListController(mMockContext, mMockPackageManager,
|
||||
createSendImageIntent("test"), null, UserHandle.USER_CURRENT,
|
||||
/* userHandle= */ UserHandle.SYSTEM);
|
||||
List<Intent> intents = new ArrayList<>();
|
||||
intents.add(createActionMainIntent());
|
||||
|
||||
List<ResolvedComponentInfo> resolvers = mController
|
||||
.getResolversForIntent(
|
||||
/* shouldGetResolvedFilter= */ true,
|
||||
/* shouldGetActivityMetadata= */ true,
|
||||
/* shouldGetOnlyDefaultActivities= */ true,
|
||||
intents);
|
||||
|
||||
assertThat(resolvers, hasSize(1));
|
||||
assertThat(resolvers.get(0).getResolveInfoAt(0), is(infos.get(0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getResolversForIntent_shouldGetOnlyDefaultActivitiesTrue_addsFlag() {
|
||||
mockStats();
|
||||
List<ResolveInfo> infos = new ArrayList<>();
|
||||
infos.add(ResolverDataProvider.createResolveInfo(0, UserHandle.USER_CURRENT));
|
||||
when(mMockPackageManager.queryIntentActivitiesAsUser(any(), anyInt(),
|
||||
any(UserHandle.class))).thenReturn(infos);
|
||||
mController = new ResolverListController(mMockContext, mMockPackageManager,
|
||||
createSendImageIntent("test"), null, UserHandle.USER_CURRENT,
|
||||
/* userHandle= */ UserHandle.SYSTEM);
|
||||
List<Intent> intents = new ArrayList<>();
|
||||
intents.add(createActionMainIntent());
|
||||
|
||||
mController
|
||||
.getResolversForIntent(
|
||||
/* shouldGetResolvedFilter= */ true,
|
||||
/* shouldGetActivityMetadata= */ true,
|
||||
/* shouldGetOnlyDefaultActivities= */ true,
|
||||
intents);
|
||||
|
||||
verify(mMockPackageManager).queryIntentActivitiesAsUser(any(),
|
||||
containsFlag(PackageManager.MATCH_DEFAULT_ONLY), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getResolversForIntent_shouldGetOnlyDefaultActivitiesFalse_doesNotAddFlag() {
|
||||
mockStats();
|
||||
List<ResolveInfo> infos = new ArrayList<>();
|
||||
infos.add(ResolverDataProvider.createResolveInfo(0, UserHandle.USER_CURRENT));
|
||||
when(mMockPackageManager.queryIntentActivitiesAsUser(any(), anyInt(),
|
||||
any(UserHandle.class))).thenReturn(infos);
|
||||
mController = new ResolverListController(mMockContext, mMockPackageManager,
|
||||
createSendImageIntent("test"), null, UserHandle.USER_CURRENT,
|
||||
/* userHandle= */ UserHandle.SYSTEM);
|
||||
List<Intent> intents = new ArrayList<>();
|
||||
intents.add(createActionMainIntent());
|
||||
|
||||
mController
|
||||
.getResolversForIntent(
|
||||
/* shouldGetResolvedFilter= */ true,
|
||||
/* shouldGetActivityMetadata= */ true,
|
||||
/* shouldGetOnlyDefaultActivities= */ false,
|
||||
intents);
|
||||
|
||||
verify(mMockPackageManager).queryIntentActivitiesAsUser(any(),
|
||||
doesNotContainFlag(PackageManager.MATCH_DEFAULT_ONLY), any());
|
||||
}
|
||||
|
||||
private int containsFlag(int flag) {
|
||||
return intThat(new FlagMatcher(flag, /* contains= */ true));
|
||||
}
|
||||
|
||||
private int doesNotContainFlag(int flag) {
|
||||
return intThat(new FlagMatcher(flag, /* contains= */ false));
|
||||
}
|
||||
|
||||
public static class FlagMatcher implements ArgumentMatcher<Integer> {
|
||||
|
||||
private final int mFlag;
|
||||
private final boolean mContains;
|
||||
|
||||
public FlagMatcher(int flag, boolean contains) {
|
||||
mFlag = flag;
|
||||
mContains = contains;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Integer integer) {
|
||||
return ((integer & mFlag) != 0) == mContains;
|
||||
}
|
||||
}
|
||||
|
||||
private UsageStats initStats(String packageName, String action,
|
||||
String annotation, int count) {
|
||||
ArrayMap<String, ArrayMap<String, Integer>> chooserCounts = new ArrayMap<>();
|
||||
@@ -174,6 +272,24 @@ public class ResolverListControllerTest {
|
||||
return sendIntent;
|
||||
}
|
||||
|
||||
private Intent createActionMainIntent() {
|
||||
Intent sendIntent = new Intent();
|
||||
sendIntent.setAction(Intent.ACTION_MAIN);
|
||||
sendIntent.addCategory(Intent.CATEGORY_LAUNCHER);
|
||||
return sendIntent;
|
||||
}
|
||||
|
||||
private void mockStats() {
|
||||
final List<UsageStats> slices = new ArrayList<>();
|
||||
ParceledListSlice<UsageStats> stats = new ParceledListSlice<>(slices);
|
||||
try {
|
||||
when(mMockService.queryUsageStats(anyInt(), anyLong(), anyLong(), anyString(),
|
||||
anyInt())).thenReturn(stats);
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private Integer getCount(
|
||||
UsageStatsManager usm, String packageName, String action, String annotation) {
|
||||
if (usm == null) {
|
||||
|
||||
@@ -618,6 +618,17 @@
|
||||
android:excludeFromRecents="true"
|
||||
android:visibleToInstantApps="true"/>
|
||||
|
||||
<activity
|
||||
android:name=".media.MediaProjectionAppSelectorActivity"
|
||||
android:theme="@style/Theme.SystemUI.MediaProjectionAppSelector"
|
||||
android:finishOnCloseSystemDialogs="true"
|
||||
android:excludeFromRecents="true"
|
||||
android:documentLaunchMode="never"
|
||||
android:relinquishTaskIdentity="true"
|
||||
android:configChanges=
|
||||
"screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
|
||||
android:visibleToInstantApps="true"/>
|
||||
|
||||
<!-- started from TvNotificationPanel -->
|
||||
<activity
|
||||
android:name=".statusbar.tv.notifications.TvNotificationPanelActivity"
|
||||
|
||||
@@ -265,6 +265,10 @@
|
||||
<style name="Animation.ShutdownUi" parent="@android:style/Animation.Toast">
|
||||
</style>
|
||||
|
||||
<style name="Theme.SystemUI.MediaProjectionAppSelector"
|
||||
parent="@*android:style/Theme.DeviceDefault.Chooser">
|
||||
</style>
|
||||
|
||||
<!-- Standard animations for hiding and showing the status bar. -->
|
||||
|
||||
<style name="Theme.SystemUI" parent="@*android:style/Theme.DeviceDefault.SystemUI">
|
||||
|
||||
@@ -43,6 +43,7 @@ import com.android.systemui.flags.FlagsModule;
|
||||
import com.android.systemui.fragments.FragmentService;
|
||||
import com.android.systemui.log.dagger.LogModule;
|
||||
import com.android.systemui.lowlightclock.LowLightClockController;
|
||||
import com.android.systemui.media.dagger.MediaProjectionModule;
|
||||
import com.android.systemui.model.SysUiState;
|
||||
import com.android.systemui.navigationbar.NavigationBarComponent;
|
||||
import com.android.systemui.plugins.BcSmartspaceDataPlugin;
|
||||
@@ -119,6 +120,7 @@ import dagger.Provides;
|
||||
FalsingModule.class,
|
||||
FlagsModule.class,
|
||||
LogModule.class,
|
||||
MediaProjectionModule.class,
|
||||
PeopleHubModule.class,
|
||||
PluginModule.class,
|
||||
PrivacyModule.class,
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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.systemui.media
|
||||
|
||||
import android.app.ActivityOptions
|
||||
import android.content.Intent
|
||||
import android.media.projection.IMediaProjection
|
||||
import android.media.projection.MediaProjectionManager.EXTRA_MEDIA_PROJECTION
|
||||
import android.os.Binder
|
||||
import android.os.Bundle
|
||||
import android.os.IBinder
|
||||
import android.view.View
|
||||
import com.android.internal.app.ChooserActivity
|
||||
import com.android.internal.app.chooser.NotSelectableTargetInfo
|
||||
import com.android.internal.app.chooser.TargetInfo
|
||||
import com.android.systemui.util.AsyncActivityLauncher
|
||||
import com.android.systemui.R;
|
||||
import javax.inject.Inject
|
||||
|
||||
class MediaProjectionAppSelectorActivity @Inject constructor(
|
||||
private val activityLauncher: AsyncActivityLauncher
|
||||
) : ChooserActivity() {
|
||||
|
||||
public override fun onCreate(bundle: Bundle?) {
|
||||
val queryIntent = Intent(Intent.ACTION_MAIN)
|
||||
.addCategory(Intent.CATEGORY_LAUNCHER)
|
||||
intent.putExtra(Intent.EXTRA_INTENT, queryIntent)
|
||||
|
||||
// TODO(b/235465652) Use resource lexeme
|
||||
intent.putExtra(Intent.EXTRA_TITLE, "Record or cast an app")
|
||||
|
||||
super.onCreate(bundle)
|
||||
|
||||
// TODO(b/235465652) we should update VisD of the title and add an icon
|
||||
findViewById<View>(R.id.title)?.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
override fun appliedThemeResId(): Int =
|
||||
R.style.Theme_SystemUI_MediaProjectionAppSelector
|
||||
|
||||
override fun startSelected(which: Int, always: Boolean, filtered: Boolean) {
|
||||
val currentListAdapter = mChooserMultiProfilePagerAdapter.activeListAdapter
|
||||
val targetInfo = currentListAdapter.targetInfoForPosition(which, filtered) ?: return
|
||||
if (targetInfo is NotSelectableTargetInfo) return
|
||||
|
||||
val intent = createIntent(targetInfo)
|
||||
|
||||
val launchToken: IBinder = Binder("media_projection_launch_token")
|
||||
val activityOptions = ActivityOptions.makeBasic()
|
||||
activityOptions.launchCookie = launchToken
|
||||
|
||||
val userHandle = mMultiProfilePagerAdapter.activeListAdapter.userHandle
|
||||
|
||||
// Launch activity asynchronously and wait for the result, launching of an activity
|
||||
// is typically very fast, so we don't show any loaders.
|
||||
// We wait for the activity to be launched to make sure that the window of the activity
|
||||
// is created and ready to be captured.
|
||||
val activityStarted = activityLauncher
|
||||
.startActivityAsUser(intent, userHandle, activityOptions.toBundle()) {
|
||||
onTargetActivityLaunched(launchToken)
|
||||
}
|
||||
|
||||
// Rely on the ActivityManager to pop up a dialog regarding app suspension
|
||||
// and return false if suspended
|
||||
if (!targetInfo.isSuspended && activityStarted) {
|
||||
// TODO(b/222078415) track activity launch
|
||||
}
|
||||
}
|
||||
|
||||
private fun createIntent(target: TargetInfo): Intent {
|
||||
val intent = Intent(target.resolvedIntent)
|
||||
|
||||
// Launch the app in a new task, so it won't be in the host's app task
|
||||
intent.flags = intent.flags or Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
|
||||
// Remove activity forward result flag as this activity will
|
||||
// return the media projection session
|
||||
intent.flags = intent.flags and Intent.FLAG_ACTIVITY_FORWARD_RESULT.inv()
|
||||
|
||||
return intent
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
activityLauncher.destroy()
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
override fun onActivityStarted(cti: TargetInfo) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
private fun onTargetActivityLaunched(launchToken: IBinder) {
|
||||
val mediaProjectionBinder = intent.getIBinderExtra(EXTRA_MEDIA_PROJECTION)
|
||||
val projection = IMediaProjection.Stub.asInterface(mediaProjectionBinder)
|
||||
|
||||
projection.launchCookie = launchToken
|
||||
|
||||
val intent = Intent()
|
||||
intent.putExtra(EXTRA_MEDIA_PROJECTION, projection.asBinder())
|
||||
setResult(RESULT_OK, intent)
|
||||
setForceSendResultForMediaProjection()
|
||||
finish()
|
||||
}
|
||||
|
||||
override fun shouldGetOnlyDefaultActivities() = false
|
||||
}
|
||||
@@ -40,7 +40,10 @@ import android.text.style.StyleSpan;
|
||||
import android.util.Log;
|
||||
import android.view.Window;
|
||||
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.flags.FeatureFlags;
|
||||
import com.android.systemui.flags.Flags;
|
||||
import com.android.systemui.statusbar.phone.SystemUIDialog;
|
||||
import com.android.systemui.util.Utils;
|
||||
|
||||
@@ -53,6 +56,7 @@ public class MediaProjectionPermissionActivity extends Activity
|
||||
private String mPackageName;
|
||||
private int mUid;
|
||||
private IMediaProjectionManager mService;
|
||||
private FeatureFlags mFeatureFlags;
|
||||
|
||||
private AlertDialog mDialog;
|
||||
|
||||
@@ -60,6 +64,7 @@ public class MediaProjectionPermissionActivity extends Activity
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
|
||||
mFeatureFlags = Dependency.get(FeatureFlags.class);
|
||||
mPackageName = getCallingPackage();
|
||||
IBinder b = ServiceManager.getService(MEDIA_PROJECTION_SERVICE);
|
||||
mService = IMediaProjectionManager.Stub.asInterface(b);
|
||||
@@ -141,14 +146,22 @@ public class MediaProjectionPermissionActivity extends Activity
|
||||
dialogTitle = getString(R.string.media_projection_dialog_title, appName);
|
||||
}
|
||||
|
||||
mDialog = new AlertDialog.Builder(this, R.style.Theme_SystemUI_Dialog)
|
||||
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this,
|
||||
R.style.Theme_SystemUI_Dialog)
|
||||
.setTitle(dialogTitle)
|
||||
.setIcon(R.drawable.ic_media_projection_permission)
|
||||
.setMessage(dialogText)
|
||||
.setPositiveButton(R.string.media_projection_action_text, this)
|
||||
.setNeutralButton(android.R.string.cancel, this)
|
||||
.setOnCancelListener(this)
|
||||
.create();
|
||||
.setOnCancelListener(this);
|
||||
|
||||
if (isPartialScreenSharingEnabled()) {
|
||||
// This is a temporary entry point before we have a new permission dialog
|
||||
// TODO(b/233183090): this activity should be redesigned to have a dropdown selector
|
||||
dialogBuilder.setNegativeButton("App", this);
|
||||
}
|
||||
|
||||
mDialog = dialogBuilder.create();
|
||||
|
||||
SystemUIDialog.registerDismissListener(mDialog);
|
||||
SystemUIDialog.applyFlags(mDialog);
|
||||
@@ -177,6 +190,15 @@ public class MediaProjectionPermissionActivity extends Activity
|
||||
if (which == AlertDialog.BUTTON_POSITIVE) {
|
||||
setResult(RESULT_OK, getMediaProjectionIntent(mUid, mPackageName));
|
||||
}
|
||||
|
||||
if (isPartialScreenSharingEnabled() && which == AlertDialog.BUTTON_NEGATIVE) {
|
||||
IMediaProjection projection = createProjection(mUid, mPackageName);
|
||||
final Intent intent = new Intent(this, MediaProjectionAppSelectorActivity.class);
|
||||
intent.putExtra(MediaProjectionManager.EXTRA_MEDIA_PROJECTION,
|
||||
projection.asBinder());
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
|
||||
startActivity(intent);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error granting projection permission", e);
|
||||
setResult(RESULT_CANCELED);
|
||||
@@ -188,10 +210,14 @@ public class MediaProjectionPermissionActivity extends Activity
|
||||
}
|
||||
}
|
||||
|
||||
private IMediaProjection createProjection(int uid, String packageName) throws RemoteException {
|
||||
return mService.createProjection(uid, packageName,
|
||||
MediaProjectionManager.TYPE_SCREEN_CAPTURE, false /* permanentGrant */);
|
||||
}
|
||||
|
||||
private Intent getMediaProjectionIntent(int uid, String packageName)
|
||||
throws RemoteException {
|
||||
IMediaProjection projection = mService.createProjection(uid, packageName,
|
||||
MediaProjectionManager.TYPE_SCREEN_CAPTURE, false /* permanentGrant */);
|
||||
IMediaProjection projection = createProjection(uid, packageName);
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(MediaProjectionManager.EXTRA_MEDIA_PROJECTION, projection.asBinder());
|
||||
return intent;
|
||||
@@ -201,4 +227,8 @@ public class MediaProjectionPermissionActivity extends Activity
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
finish();
|
||||
}
|
||||
|
||||
private boolean isPartialScreenSharingEnabled() {
|
||||
return mFeatureFlags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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.systemui.media.dagger
|
||||
|
||||
import android.app.Activity
|
||||
import com.android.systemui.media.MediaProjectionAppSelectorActivity
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.multibindings.ClassKey
|
||||
import dagger.multibindings.IntoMap
|
||||
|
||||
@Module
|
||||
abstract class MediaProjectionModule {
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(MediaProjectionAppSelectorActivity::class)
|
||||
abstract fun provideMediaProjectionAppSelectorActivity(
|
||||
activity: MediaProjectionAppSelectorActivity): Activity
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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.systemui.util
|
||||
|
||||
import android.app.IActivityTaskManager
|
||||
import android.app.WaitResult
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.UserHandle
|
||||
import com.android.systemui.dagger.qualifiers.Main
|
||||
import com.android.systemui.dagger.qualifiers.UiBackground
|
||||
import java.util.concurrent.Executor
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Helper class that allows to launch an activity and asynchronously wait
|
||||
* for it to be launched. This class uses application context, so the intent
|
||||
* will be launched with FLAG_ACTIVITY_NEW_TASK.
|
||||
*/
|
||||
class AsyncActivityLauncher @Inject constructor(
|
||||
private val context: Context,
|
||||
private val activityTaskManager: IActivityTaskManager,
|
||||
@UiBackground private val backgroundExecutor: Executor,
|
||||
@Main private val mainExecutor: Executor
|
||||
) {
|
||||
|
||||
private var pendingCallback: ((WaitResult) -> Unit)? = null
|
||||
|
||||
/**
|
||||
* Starts activity and notifies about the result using the provided [callback].
|
||||
* If there is already pending activity launch the call will be ignored.
|
||||
*
|
||||
* @return true if launch has started, false otherwise
|
||||
*/
|
||||
fun startActivityAsUser(intent: Intent, userHandle: UserHandle,
|
||||
activityOptions: Bundle? = null,
|
||||
callback: (WaitResult) -> Unit): Boolean {
|
||||
if (pendingCallback != null) return false
|
||||
|
||||
pendingCallback = callback
|
||||
|
||||
intent.flags = intent.flags or Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
|
||||
backgroundExecutor.execute {
|
||||
val waitResult = activityTaskManager.startActivityAndWait(
|
||||
/* caller = */ null,
|
||||
/* callingPackage = */ context.packageName,
|
||||
/* callingFeatureId = */ context.attributionTag,
|
||||
/* intent = */ intent,
|
||||
/* resolvedType = */ null,
|
||||
/* resultTo = */ null,
|
||||
/* resultWho = */ null,
|
||||
/* requestCode = */ 0,
|
||||
/* flags = */ 0,
|
||||
/* profilerInfo = */ null,
|
||||
/* options = */ activityOptions,
|
||||
/* userId = */ userHandle.identifier
|
||||
)
|
||||
mainExecutor.execute {
|
||||
pendingCallback?.invoke(waitResult)
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels pending activity launches. It guarantees that the callback won't be fired
|
||||
* but the activity will be launched anyway.
|
||||
*/
|
||||
fun destroy() {
|
||||
pendingCallback = null
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user