diff --git a/app/src/main/java/io/github/muntashirakon/AppManager/accessibility/activity/LeadingActivityTrackerActivity.java b/app/src/main/java/io/github/muntashirakon/AppManager/accessibility/activity/LeadingActivityTrackerActivity.java index 0f8bf527cc6..b4ccb651187 100644 --- a/app/src/main/java/io/github/muntashirakon/AppManager/accessibility/activity/LeadingActivityTrackerActivity.java +++ b/app/src/main/java/io/github/muntashirakon/AppManager/accessibility/activity/LeadingActivityTrackerActivity.java @@ -18,6 +18,9 @@ import io.github.muntashirakon.AppManager.R; import io.github.muntashirakon.AppManager.accessibility.AccessibilityMultiplexer; import io.github.muntashirakon.AppManager.accessibility.NoRootAccessibilityService; +import io.github.muntashirakon.AppManager.self.SelfPermissions; +import io.github.muntashirakon.AppManager.settings.FeatureController; +import io.github.muntashirakon.AppManager.utils.ThreadUtils; public class LeadingActivityTrackerActivity extends BaseActivity { private final ActivityResultLauncher mSettingsLauncher = registerForActivityResult( @@ -25,6 +28,11 @@ public class LeadingActivityTrackerActivity extends BaseActivity { // Init again init(); }); + private final ActivityResultLauncher mUsageAccessSettingsLauncher = registerForActivityResult( + new ActivityResultContracts.StartActivityForResult(), result -> { + // Init again + init(); + }); @Override protected void onAuthenticated(@Nullable Bundle savedInstanceState) { @@ -51,6 +59,18 @@ private void init() { .show(); return; } + if (!SelfPermissions.checkUsageStatsPermission()) { + ThreadUtils.postOnMainThread(() -> new MaterialAlertDialogBuilder(this) + .setTitle(R.string.grant_usage_access) + .setMessage(R.string.grant_usage_acess_message) + .setCancelable(false) + .setPositiveButton(R.string.go, (dialog, which) -> { + mUsageAccessSettingsLauncher.launch(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS)); + }) + .setNegativeButton(R.string.go_back, (dialog, which) -> finish()) + .show()); + return; + } if (!NoRootAccessibilityService.isAccessibilityEnabled(this)) { new MaterialAlertDialogBuilder(this) .setTitle(R.string.grant_required_permission) diff --git a/app/src/main/java/io/github/muntashirakon/AppManager/accessibility/activity/TrackerWindow.java b/app/src/main/java/io/github/muntashirakon/AppManager/accessibility/activity/TrackerWindow.java index 345f4c19b93..03af0399e10 100644 --- a/app/src/main/java/io/github/muntashirakon/AppManager/accessibility/activity/TrackerWindow.java +++ b/app/src/main/java/io/github/muntashirakon/AppManager/accessibility/activity/TrackerWindow.java @@ -3,6 +3,7 @@ package io.github.muntashirakon.AppManager.accessibility.activity; import android.annotation.SuppressLint; +import android.app.usage.UsageEvents; import android.content.Context; import android.content.Intent; import android.graphics.PixelFormat; @@ -29,11 +30,13 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.concurrent.Future; import io.github.muntashirakon.AppManager.BuildConfig; import io.github.muntashirakon.AppManager.R; import io.github.muntashirakon.AppManager.accessibility.AccessibilityMultiplexer; +import io.github.muntashirakon.AppManager.compat.UsageStatsManagerCompat; import io.github.muntashirakon.AppManager.details.AppDetailsActivity; import io.github.muntashirakon.AppManager.utils.ThreadUtils; import io.github.muntashirakon.AppManager.utils.UIUtils; @@ -48,6 +51,7 @@ public class TrackerWindow implements View.OnTouchListener { private final ShapeableImageView mIconView; private final MaterialCardView mContentView; private final TextInputTextView mPackageNameView; + private final TextInputTextView mActivityNameView; private final TextInputTextView mClassNameView; private final TextInputTextView mClassHierarchyView; private final MaterialButton mPlayPauseButton; @@ -83,6 +87,7 @@ public TrackerWindow(@NonNull Context context) { mIconView = mView.findViewById(R.id.icon); mContentView = mView.findViewById(R.id.content); mPackageNameView = mView.findViewById(R.id.package_name); + mActivityNameView = mView.findViewById(R.id.activity_name); mClassNameView = mView.findViewById(R.id.class_name); mClassHierarchyView = mView.findViewById(R.id.class_hierarchy); mPlayPauseButton = mView.findViewById(R.id.action_play_pause); @@ -94,6 +99,14 @@ public TrackerWindow(@NonNull Context context) { copyText("Package name", packageName); return true; }); + mActivityNameView.setOnLongClickListener(v -> { + Editable activityName = mActivityNameView.getText(); + if (TextUtils.isEmpty(activityName)) { + return false; + } + copyText("Activity name", activityName); + return true; + }); mClassNameView.setOnLongClickListener(v -> { Editable className = mClassNameView.getText(); if (TextUtils.isEmpty(className)) { @@ -120,7 +133,7 @@ public TrackerWindow(@NonNull Context context) { try { context.startActivity(appInfoIntent); } catch (Throwable th) { - UIUtils.displayLongToast(th.getMessage()); + UIUtils.displayLongToast("Error: " + th.getMessage()); } }); mView.findViewById(R.id.mini).setOnClickListener(v -> iconify()); @@ -191,7 +204,11 @@ public void showOrUpdate(AccessibilityEvent event) { mClassNameView.setText(event.getClassName()); mClassHierarchyResult = ThreadUtils.postOnBackgroundThread(() -> { CharSequence classHierarchy = TextUtils.join("\n", getClassHierarchy(event)); - ThreadUtils.postOnMainThread(() -> mClassHierarchyView.setText(classHierarchy)); + String activityName = getActivityName(event); + ThreadUtils.postOnMainThread(() -> { + mActivityNameView.setText(activityName); + mClassHierarchyView.setText(classHierarchy); + }); }); } } @@ -247,6 +264,38 @@ private void copyText(CharSequence label, CharSequence content) { Utils.copyToClipboard(mView.getContext(), label, content); } + @Nullable + public String getActivityName(@NonNull AccessibilityEvent event) { + if (event.getPackageName() == null) { + return null; + } + String packageName = event.getPackageName().toString(); + UsageEvents.Event usageEvent = new UsageEvents.Event(); + long currentTimeMillis = System.currentTimeMillis(); + long timeDiff = 5_000; + int tries = 0; + do { + UsageEvents queryEvents = UsageStatsManagerCompat.queryEvents(currentTimeMillis - timeDiff, + currentTimeMillis, UserHandleHidden.myUserId()); + long lastTime = 0L; + String activityName = null; + while (queryEvents.hasNextEvent()) { + queryEvents.getNextEvent(usageEvent); + if (usageEvent.getEventType() == UsageEvents.Event.ACTIVITY_RESUMED + && Objects.equals(packageName, usageEvent.getPackageName()) + && lastTime < usageEvent.getTimeStamp()) { + lastTime = usageEvent.getTimeStamp(); + activityName = usageEvent.getClassName(); + } + } + if (activityName != null) { + return activityName; + } + timeDiff *= 60; + } while ((++tries) != 3); + return null; + } + @NonNull private static List getClassHierarchy(@NonNull AccessibilityEvent event) { List classHierarchies = new ArrayList<>(); diff --git a/app/src/main/res/layout/window_activity_tracker.xml b/app/src/main/res/layout/window_activity_tracker.xml index 6514b1e4f5e..c46a16d1494 100644 --- a/app/src/main/res/layout/window_activity_tracker.xml +++ b/app/src/main/res/layout/window_activity_tracker.xml @@ -52,6 +52,24 @@ + + + + + +