Skip to content

Instantly share code, notes, and snippets.

@Bringoff
Last active January 27, 2025 16:28
Show Gist options
  • Select an option

  • Save Bringoff/97dee6e8e711223b0b74b389df8bc390 to your computer and use it in GitHub Desktop.

Select an option

Save Bringoff/97dee6e8e711223b0b74b389df8bc390 to your computer and use it in GitHub Desktop.
@Override
public void onAccessibilityEvent(final AccessibilityEvent event) {
...
UsageAccessHelper.ActivityData realActivity = appStatsHelper.getCurrentActivity();
realActivityName = realActivity.getActivityFullName();
checkIfPictureInPicture(realActivityName);
}
private void checkIfPictureInPicture(String activityName) {
if ("com.android.systemui/.pip.phone.PipMenuActivity".equals(activityName)) {
notificationService.fireNotificationAsync(Notifications.PICTURE_IN_PICTURE_MODE_ACTIVATED);
}
}
...
@Nullable
@Override
public ActivityData getCurrentActivity() {
try {
long ts = System.currentTimeMillis();
UsageEvents queryEvents = usageStatsManager.queryEvents(ts - STATS_INTERVAL, ts);
String activityName = null;
String packageName = null;
int eventCount = 0;
while (queryEvents.hasNextEvent()) {
queryEvents.getNextEvent(eventOut);
if (!TextUtils.isEmpty(eventOut.getPackageName()) && eventOut.getEventType() == UsageEvents.Event.MOVE_TO_FOREGROUND) {
packageName = eventOut.getPackageName();
activityName = eventOut.getClassName();
}
eventCount++;
}
if (TextUtils.isEmpty(packageName)) {
return null;
}
if (eventCount == 0) {
logger.debug(LOG_TAG + "usage stats contains no events for last %d ms", STATS_INTERVAL);
}
return new ActivityData(packageName, activityName);
} catch (Exception e) {
logger.error("[UsageAccessHelper50] cannot query usage events: %s", e);
return null;
}
}
...
@ToString
@AllArgsConstructor
class ActivityData {
public String packageName;
public String activityName;
public ActivityData(String fullActivityName) {
try {
String[] data = fullActivityName.split("/");
packageName = data[0];
activityName = data[1];
} catch (Exception e) {
packageName = "";
activityName = null;
}
}
public String getActivityFullName() {
return TextUtils.isEmpty(packageName) || TextUtils.isEmpty(activityName) ? "" :
packageName + "/" + activityName;
}
}
/**
* This Activity does nothing except closing itself. Used to close Picture-in-Picture window opened
* by another app.
*/
public class FakePictureInPictureActivity extends AppCompatActivity {
public static Intent getStartIntent(@NonNull Context context) {
return new Intent(context, FakePictureInPictureActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
public static boolean isRunning() {
return isAlreadyRunning;
}
private static boolean isAlreadyRunning = false;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FrameLayout root = new FrameLayout(this);
root.setId(R.id.nationaledtech_fake_picture_in_picture_container);
setContentView(root);
}
@Override
protected void onStart() {
super.onStart();
isAlreadyRunning = true;
}
@Override
protected void onStop() {
super.onStop();
isAlreadyRunning = false;
}
@Override
protected void onResume() {
super.onResume();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
&& getPackageManager().hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)
&& !isInPictureInPictureMode()) {
try {
enterPictureInPictureMode(new PictureInPictureParams.Builder().build());
} catch (Exception e) {
MobivementApplication.getMobivementContext()
.getLogger().error("[FakePictureInPictureActivity] Cannot enter PiP mode: %s", e);
}
}
}
@Override
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode, Configuration newConfig) {
super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig);
if (isInPictureInPictureMode) {
try {
moveTaskToBack(false);
finishAndRemoveTask();
} catch (Exception e) {
MobivementApplication.getMobivementContext()
.getLogger().error("[FakePictureInPictureActivity]Cannot exit PiP mode: %s", e);
}
}
}
}
@RequiredArgsConstructor
public class PictureInPictureActivationListener implements NotificationListener {
private final Context context;
private final Logger logger;
@Override
public void onNotification(String category, Bundle extras) {
if (!Notifications.PICTURE_IN_PICTURE_MODE_ACTIVATED.equals(category)) {
return;
}
logger.info("[PictureInPictureActivationListener] picture-in-picture detected");
if (isDefinitelyHasPictureInPictureApi() && !isOurPictureInPictureActivityRunning()) {
logger.info("[PictureInPictureActivationListener]" +
"picture-in-picture is not allowed at the moment");
ContextCompat.startActivitн(context, FakePictureInPictureActivity.getStartIntent(context), null);
}
}
private boolean isDefinitelyHasPictureInPictureApi() {
PackageManager packageManager = context.getPackageManager();
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
&& packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE);
}
private boolean isOurPictureInPictureActivityRunning() {
return FakePictureInPictureActivity.isRunning();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment