Как `getTopActivity` name или получить имя запущенного в данный момент пакета приложения в lollipop?

Я создаю приложение блокировки приложения. Как получить текущее бегущее задание в леденце на палочке? getRunningTaskinfo метод устарел в lollipop API, тогда как решить эту проблему?

10 ответов

Решение

Попробуй это:

ActivityManager mActivityManager =(ActivityManager)this.getSystemService(Context.ACTIVITY_SERVICE);

if(Build.VERSION.SDK_INT > 20){
String mPackageName = mActivityManager.getRunningAppProcesses().get(0).processName;
}
else{
  String mpackageName = mActivityManager.getRunningTasks(1).get(0).topActivity.getPackageName();
}

мы можем получить с помощью UsageStats:

public static String getTopAppName(Context context) {
    ActivityManager mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    String strName = "";
    try {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            strName = getLollipopFGAppPackageName(context);
        } else {
            strName = mActivityManager.getRunningTasks(1).get(0).topActivity.getClassName();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return strName;
}


private static String getLollipopFGAppPackageName(Context ctx) {

    try {
        UsageStatsManager usageStatsManager = (UsageStatsManager) ctx.getSystemService("usagestats");
        long milliSecs = 60 * 1000;
        Date date = new Date();
        List<UsageStats> queryUsageStats = usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, date.getTime() - milliSecs, date.getTime());
        if (queryUsageStats.size() > 0) {
            Log.i("LPU", "queryUsageStats size: " + queryUsageStats.size());
        }
        long recentTime = 0;
        String recentPkg = "";
        for (int i = 0; i < queryUsageStats.size(); i++) {
            UsageStats stats = queryUsageStats.get(i);
            if (i == 0 && !"org.pervacio.pvadiag".equals(stats.getPackageName())) {
                Log.i("LPU", "PackageName: " + stats.getPackageName() + " " + stats.getLastTimeStamp());
            }
            if (stats.getLastTimeStamp() > recentTime) {
                recentTime = stats.getLastTimeStamp();
                recentPkg = stats.getPackageName();
            }
        }
        return recentPkg;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return "";
}

// ВКЛЮЧИТЬ USAGE_STATS

    // Declare USAGE_STATS permisssion in manifest

    <uses-permission
    android:name="android.permission.PACKAGE_USAGE_STATS"
    tools:ignore="ProtectedPermissions" />


    Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
    startActivity(intent);

Ниже приведено лучшее решение для получения приложения "Запуск" в API 21 или выше. эта работа для меня

private String retriveNewApp() {
    if (VERSION.SDK_INT >= 21) {
        String currentApp = null;
        UsageStatsManager usm = (UsageStatsManager) this.getSystemService(Context.USAGE_STATS_SERVICE);
        long time = System.currentTimeMillis();
        List<UsageStats> applist = usm.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000 * 1000, time);
        if (applist != null && applist.size() > 0) {
            SortedMap<Long, UsageStats> mySortedMap = new TreeMap<>();
            for (UsageStats usageStats : applist) {
                mySortedMap.put(usageStats.getLastTimeUsed(), usageStats);
            }
            if (mySortedMap != null && !mySortedMap.isEmpty()) {
                currentApp = mySortedMap.get(mySortedMap.lastKey()).getPackageName();
            }
        }
        Log.e(TAG, "Current App in foreground is: " + currentApp);

        return currentApp;

    }
    else {

        ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        String mm=(manager.getRunningTasks(1).get(0)).topActivity.getPackageName();
        Log.e(TAG, "Current App in foreground is: " + mm);
        return mm;
    }
}

Вы можете использовать AccessibilityService, чтобы получить текущее приложение Running. Служба специальных возможностей предоставляет событие onAccessibilityEvent.

Ниже приведен пример кода.

@Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
            if (event.getPackageName() != null && event.getClassName() != null) {
                Log.d("Foreground App", event.getPackageName().toString());  

            }
        }
    }

Вы можете найти больше информации о Сервисе Доступности здесь

согласно этому ; следующий код отлично работает для меня:

MOVE_TO_FOREGROUND и MOVE_TO_BACKGROUND добавлены в SDK 21 и устарели в SDK 29

ACTIVITY_RESUMED и ACTIVITY_PAUSED добавлены в SDK 29

      public static String getRunningPackageName(Context context) {
    String packageName = null;

    UsageStatsManager mUsageStatsManager = (UsageStatsManager) context
            .getSystemService(Context.USAGE_STATS_SERVICE);

    final long INTERVAL = 1000 * 60;
    final long end = System.currentTimeMillis();
    final long begin = end - INTERVAL;
    final UsageEvents usageEvents = mUsageStatsManager.queryEvents(begin, end);
    while (usageEvents.hasNextEvent()) {
        UsageEvents.Event event = new UsageEvents.Event();
        usageEvents.getNextEvent(event);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            switch (event.getEventType()) {
                case UsageEvents.Event.ACTIVITY_RESUMED:
                    packageName = event.getPackageName();
                    break;
                case UsageEvents.Event.ACTIVITY_PAUSED:
                    if (event.getPackageName().equals(packageName)) {
                        packageName = null;
                    }
            }
        }else {
            switch (event.getEventType()) {
                case UsageEvents.Event.MOVE_TO_FOREGROUND:
                    packageName = event.getPackageName();
                    break;
                case UsageEvents.Event.MOVE_TO_BACKGROUND:
                    if (event.getPackageName().equals(packageName)) {
                        packageName = null;
                    }
            }
        }
    }

    return packageName;
}

Уверены ли вы? Как я вижу по последним документам для Android, обновление LOLLIPOP не позволяет вам узнать какую-либо информацию о других приложениях, кроме ваших собственных!?

http://developer.android.com/reference/android/app/ActivityManager.html Вы можете видеть, что все эти методы устарели!

Попробуйте это.. Это сработало для меня.

ActivityManager activityManager = (ActivityManager) getSystemService (Context.ACTIVITY_SERVICE);

if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP)    
{

String packageName = activityManager.getRunningAppProcesses().get(0).processName;
} 
else if(Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP)
{
String packageName =  ProcessManager.getRunningForegroundApps(getApplicationContext()).get(0).getPackageName();

}
else
{
String packageName = activityManager.getRunningTasks(1).get(0).topActivity.getPackageName();
}

Ответ @Manish Godhani ( /questions/17453618/kak-gettopactivity-name-ili-poluchit-imya-zapuschennogo-v-dannyij-moment-paketa-prilozheniya-v-lollipop/17453619#17453619) работает очень хорошо, но вы должны дать соответствующие разрешения для этого!

Посмотрите два первых пункта этого ответа: /questions/1288876/kak-ispolzovat-usagestatsmanager/1288917#1288917

Это работает для меня (до добавления разрешений я тоже получал 'null'), как показано ниже: Результаты, представленные кодом этого ответа, после добавления разрешений

Существует три способа отображения названия текущего действия на экране.

Через UsageStatsManager

Для этого способа требуется дополнительное разрешение для пользователя, и пользователю необходимо вручную включить это разрешение для вашего приложения.

Вам нужно сначала добавить разрешение в свой манифест

      <uses-permission 
android:name="android.permission.PACKAGE_USAGE_STATS"
tools:ignore="ProtectedPermissions" />

Затем перенаправьте пользователя, чтобы включить это разрешение с помощью этого кода:

      val intent = Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS)
startActivity(intent)

После добавления этого разрешения вы можете получить имя текущего действия с помощью этого кода:

      var lastActivityName: String? = null
private fun getCurrentActivityName(): String? {
    val usageStatsManager =
        applicationContext.getSystemService(USAGE_STATS_SERVICE) as UsageStatsManager
    try {
        val currentTimeMillis = System.currentTimeMillis()
        var activityName: String? = null
        var packageName: String? = null
        val queryEvents = usageStatsManager.queryEvents(
            currentTimeMillis - 60000.toLong(),
            currentTimeMillis
        )
        while (queryEvents.hasNextEvent()) {
            val event = UsageEvents.Event()
            queryEvents.getNextEvent(event)
            if (event.eventType == 1) {
                packageName = event.packageName
                activityName = event.className
            }
            else if (event.eventType == 2) {
                if (event.packageName != packageName) {
                    break
                }
                packageName = null
            }
        }
        return if (packageName != null && activityName != null) {
            lastActivityName = activityName
            activityName
        } else lastActivityName
    } catch (e: Exception) {
        e.printStackTrace()
    }
    return null
}

я добавилlastActivityNameпотому что иногда вы можете получить значение null в одном и том же действии, поэтому вы можете удалить его.

Через доступность

Это можно сделать через Службу доступности. Но начиная с Android 11 вы не можете получить список других имен пакетов без добавления этого специального разрешения.

      <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>

<queries>
    <intent>
        <action android:name="android.intent.action.MAIN" />
    </intent>
</queries>

Но проблема в том, что GooglePlay может отклонить ваше приложение, если у вас нет веских объяснений.

Сначала я покажу вам, как получить имя текущего действия с помощью этого специального разрешения, а затем добавлю трюк, как получить действие без добавления этого разрешения, используя только службу специальных возможностей.

Для настройки службы доступности вам необходимо добавить это вres/xml/accessibility_setting.xml(имя файла может быть любым)

      <?xml version="1.0" encoding="utf-8"?>

<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
   android:accessibilityFeedbackType="feedbackGeneric"
   android:accessibilityFlags="flagDefault|flagReportViewIds|flagIncludeNotImportantViews"
   android:accessibilityEventTypes="typeWindowStateChanged"
   android:canRequestFilterKeyEvents="true"
   android:canRetrieveWindowContent="true" />

Затем вам нужно добавить службу специальных возможностей в Manifest.xml, как показано ниже:

      <service
     android:name=".services.MyAccessibilityService"
     android:label="@string/app_name"
     android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
     android:exported="true">

        <intent-filter>
            <action android:name="android.accessibilityservice.AccessibilityService" />
        </intent-filter>

        <meta-data
            android:name="android.accessibilityservice"
            android:resource="@xml/accessibility_setting" />
</service>

Следующим будет определение нашегоMyAccessibilityServiceкласс обслуживания и функция для получения имени текущего действия:

Должно быть так:

      class MyAccessibilityService : AccessibilityService() {

   var currentActivityName : String? = null

   override fun onServiceConnected() {
       //Define your initial configs here
   }

   @Synchronized
   override fun onAccessibilityEvent(event: AccessibilityEvent) {
       checkForCurrentActivity(event)
   }

   override fun onInterrupt() {
       // define your interruption code here
   }

ТогдаcheckForCurrentActivity(event)было бы:

      private fun checkForCurrentActivity(event: AccessibilityEvent) {
    if (event.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
        if (event.packageName != null && event.className != null) {
            val componentName = ComponentName(
                event.packageName.toString(),
                event.className.toString()
            )
            if (isActivity(componentName)) {
                val componentFlattenName = componentName.flattenToShortString()
                currentActivityName = componentFlattenName.replace("/.", ".")
                if (currentActivityName.contains("/")) {
                    currentActivityName = currentActivityName.split("/".toRegex())[1]
                }
            }
        }
    }
}

private fun isActivity(componentName: ComponentName): Boolean {
    return try {
        packageManager.getActivityInfo(componentName, 0)
    } catch (e: PackageManager.NameNotFoundException) {
        null
    } != null
}

И, наконец, вы можете легко получить имя текущего действия, используя

Через специальные возможности (без дополнительных разрешений)

В конце я покажу вам способ получить имя текущего действия только с разрешением доступа, без использованияQUERY_ALL_PACKAGES.

Это решение основано на втором решении, но с небольшим отличием. Для этого взлома вам нужно заменитьisActivity(componentName)с:

      private fun isActivity(componentName: ComponentName):Boolean {
    val name = componentName.flattenToShortString()
    return name.contains("/") &&
        !name.contains("com.android.systemui") &&
        !name.contains("Layout") &&
        !name.contains(".widget") &&
        !name.contains("android.view") &&
        !name.contains("android.material") &&
        !name.contains("android.inputmethodservice") &&
        !name.contains("$") &&
        !name.contains("android.view") &&
        !name.contains("android.app.dialog")
}

И, как и раньше, вы можете легко получить имя текущего действия, используяcurrentActivityName

Этот хак работает почти с 99% точностью.

Может быть достигнуто как это.....

ActivityManager am =(ActivityManager)context.getSystemService(ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1);
ActivityManager.RunningTaskInfo task = tasks.get(0); // current task
ComponentName rootActivity = task.baseActivity;


rootActivity.getPackageName();//*currently active applications package name*

Для леденцов:

ActivityManager mActivityManager =(ActivityManager)this.getSystemService(Context.ACTIVITY_SERVICE);

if(Build.VERSION.SDK_INT > 20){
    String activityName =mActivityManager.getRunningAppProcesses().get(0).processName;
 }
else{
 String activityName =   mActivityManager.getRunningTasks(1).get(0).topActivity.getPackageName();
}

для полного примера проверьте это...

Я использую хакерский способ получения имени топ-активности. Всякий раз, когда я создаю или возобновляю действие, я сохраняю имя в Sharedpreferences. Я создал две функции для сохранения и получения topClass в SharedPreferences. Это всегда перезаписывает последнюю активность и дает верхнюю активность. Мне не нужно беспокоиться о разрешениях и уровнях API. Довольно простой, но определенно не лучший способ сделать это.

Другие вопросы по тегам