Il semble que Google ait finalement fermé toutes les portes pour obtenir le package d'application de premier plan actuel.
Après la mise à jour de Lollipop, qui a tué getRunningTasks(int maxNum)
et grâce à cette réponse , j'ai utilisé ce code pour obtenir le package d'application de premier plan depuis Lollipop:
final int PROCESS_STATE_TOP = 2;
RunningAppProcessInfo currentInfo = null;
Field field = null;
try {
field = RunningAppProcessInfo.class.getDeclaredField("processState");
} catch (Exception ignored) {
}
ActivityManager am = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> appList = am.getRunningAppProcesses();
for (RunningAppProcessInfo app : appList) {
if (app.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND &&
app.importanceReasonCode == 0 ) {
Integer state = null;
try {
state = field.getInt( app );
} catch (Exception ignored) {
}
if (state != null && state == PROCESS_STATE_TOP) {
currentInfo = app;
break;
}
}
}
return currentInfo;
Android 5.1.1 et supérieur (6.0 Marshmallow), semble-t-il, tué getRunningAppProcesses()
. Il retourne maintenant une liste de votre propre package d'application.
UsageStatsManager
Nous pouvons utiliser la nouvelle API UsageStatsManager
comme décrite ici mais cela ne fonctionne pas pour toutes les applications. Certaines applications système renverront le même package
com.google.Android.googlequicksearchbox
AccessibilityService (décembre 2017: interdiction d'utilisation par Google)
Certaines applications utilisent AccessibilityService
(comme vu ici ), mais cela présente certains inconvénients.
Existe-t-il un autre moyen d'obtenir le package d'application en cours d'exécution?
Pour obtenir la liste des processus en cours d'exécution sur Android 1.6 - Android 6.0, vous pouvez utiliser cette bibliothèque. J'ai écrit: https://github.com/jaredrummler/AndroidProcesses = La bibliothèque lit/proc pour obtenir des informations sur le processus.
Google a considérablement restreint l'accès à/proc dans Android Nougat. Pour obtenir la liste des processus en cours d'exécution sur Android Nougat, vous devez utiliser UsageStatsManager ou disposer d'un accès root.
Cliquez sur l'historique des modifications pour les solutions alternatives précédentes.
private String printForegroundTask() {
String currentApp = "NULL";
if(Android.os.Build.VERSION.SDK_INT >= Android.os.Build.VERSION_CODES.Lollipop) {
UsageStatsManager usm = (UsageStatsManager)this.getSystemService("usagestats");
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<Long, UsageStats>();
for (UsageStats usageStats : appList) {
mySortedMap.put(usageStats.getLastTimeUsed(), usageStats);
}
if (mySortedMap != null && !mySortedMap.isEmpty()) {
currentApp = mySortedMap.get(mySortedMap.lastKey()).getPackageName();
}
}
} else {
ActivityManager am = (ActivityManager)this.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> tasks = am.getRunningAppProcesses();
currentApp = tasks.get(0).processName;
}
Log.e("adapter", "Current App in foreground is: " + currentApp);
return currentApp;
}
Utilisez cette méthode pour obtenir une tâche de premier plan. U aura besoin d'une autorisation système "Android: get_usage_stats"
public static boolean needPermissionForBlocking(Context context){
try {
PackageManager packageManager = context.getPackageManager();
ApplicationInfo applicationInfo = packageManager.getApplicationInfo(context.getPackageName(), 0);
AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
int mode = appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, applicationInfo.uid, applicationInfo.packageName);
return (mode != AppOpsManager.MODE_ALLOWED);
} catch (PackageManager.NameNotFoundException e) {
return true;
}
}
SI l’utilisateur l’autorise dans le réglage -> Sécurité-> application avec accès utilisateur. Après cela, vous aurez une tâche de premier plan. Processus similaire Clean matser de Cheetahamobile Lien de lecture Google
Jetez un oeil à https://github.com/ricvalerio/foregroundappchecker , ce pourrait être ce dont vous avez besoin. Fournit un exemple de code et évite d'avoir à mettre en œuvre un détecteur de premier plan en version croisée.
Voici deux exemples:
AppChecker appChecker = new AppChecker();
String packageName = appChecker.getForegroundApp();
Ou vérifiez régulièrement:
AppChecker appChecker = new AppChecker();
appChecker
.when("com.other.app", new AppChecker.Listener() {
@Override
public void onForeground(String packageName) {
// do something
}
)
.when("com.my.app", new AppChecker.Listener() {
@Override
public void onForeground(String packageName) {
// do something
}
)
.other(new AppChecker.Listener() {
@Override
public void onForeground(String packageName) {
// do something
}
)
.timeout(1000)
.start(this);
Google a limité cette fonctionnalité pour les applications système uniquement. Comme indiqué dans un ticket de bogue , vous aurez besoin de l'autorisation REAL_GET_TASKS pour y accéder.
Les applications doivent maintenant avoir ... permission.REAL_GET_TASKS pour pouvoir obtenir des informations sur les processus pour toutes les applications. Seules les informations de processus de l'application appelante seront renvoyées si l'application ne dispose pas de l'autorisation. Les applications Privilèges pourront temporairement obtenir des informations sur les processus de toutes les applications si elles ne disposent pas de la nouvelle autorisation mais sont dépréciées ... permission.GET_TASKS De plus, seules les applications système peuvent obtenir l'autorisation REAL_GET_TASKS.
Je viens de lancer une optimisation potentielle de ce que j'imagine être un morceau de code fortement copié-collé pour détecter l'application la plus performante sur Android M.
Cette
if (Android.os.Build.VERSION.SDK_INT >= Android.os.Build.VERSION_CODES.Lollipop) {
UsageStatsManager usm = (UsageStatsManager)this.getSystemService("usagestats");
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<Long, UsageStats>();
for (UsageStats usageStats : appList) {
mySortedMap.put(usageStats.getLastTimeUsed(), usageStats);
}
if (mySortedMap != null && !mySortedMap.isEmpty()) {
currentApp = mySortedMap.get(mySortedMap.lastKey()).getPackageName();
}
}
}
Peut être simplifié à cela
if (Android.os.Build.VERSION.SDK_INT >= Android.os.Build.VERSION_CODES.Lollipop) {
UsageStatsManager usm = (UsageStatsManager) context.getSystemService(
Context.USAGE_STATS_SERVICE);
long time = System.currentTimeMillis();
List<UsageStats> appStatsList = usm.queryUsageStats(UsageStatsManager.INTERVAL_DAILY,
time - 1000 * 1000, time);
if (appStatsList != null && !appStatsList.isEmpty()) {
currentApp = Collections.max(appStatsList, (o1, o2) ->
Long.compare(o1.getLastTimeUsed(), o2.getLastTimeUsed())).getPackageName();
}
}
Je me suis retrouvé à utiliser ce code dans une boucle de 2 secondes et je me suis demandé pourquoi j'utilisais une solution complexe qui était O (n * log (n)), alors qu'une solution plus simple était disponible dans Collections.max (), à savoir O (n ).
// Cela fonctionne plus vite que la réponse ci-dessus.
String mforegoundPppPackageName;
UsageStatsManager usage = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
long time = System.currentTimeMillis();
List<UsageStats> stats = usage.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, 0, time);
Collections.sort(stats, usageStatsComparator);
if (stats != null && stats.size() > 0) {
if (stats.get(stats.size()).getPackageName().equals("Android")) {
stats.remove(stats.size());
}
mforegoundPppPackageName = stats.get(stats.size()).getPackageName();
} else {
mforegoundPppPackageName = "";
}
**//How to sort**
Comparator<UsageStats> usageStatsComparator = new Comparator<UsageStats>() {
@Override
public int compare(UsageStats o1, UsageStats o2) {
if (o1.getLastTimeUsed() > o2.getLastTimeUsed()) {
return 1;
} else if (o1.getLastTimeUsed() < o2.getLastTimeUsed()) {
return -1;
} else {
return 0;
}
}
};
public class AccessibilityDetectingService extends AccessibilityService {
@Override
protected void onServiceConnected() {
super.onServiceConnected();
//Configure these here for compatibility with API 13 and below.
AccessibilityServiceInfo config = new AccessibilityServiceInfo();
config.eventTypes = AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
config.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
if (Build.VERSION.SDK_INT >= 16)
//Just in case this helps
config.flags = AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
setServiceInfo(config);
}
@Override
public void onAccessibilityEvent(final AccessibilityEvent event) {
if (event == null ) {
return;
} else if(event.getPackageName() == null && event.getClassName() == null){
return;
}
if (activityInfo != null){
Log.d("CurrentActivity", componentName.flattenToShortString());
}
}
private ActivityInfo tryGetActivity(ComponentName componentName) {
try {
return getPackageManager().getActivityInfo(componentName, 0);
} catch (PackageManager.NameNotFoundException e) {
return null;
}
}
@Override
public void onInterrupt() {
}
}
}//`enter code here`uses-permission Android:name="Android.permission.BIND_ACCESSIBILITY_SERVICE" />
<uses-permission Android:name="Android.permission.GET_TASKS" />
Ensuite, démarrez le service et l'accessibilité de l'application dans le réglage de votre appareil-> accessibilité-> App sur ce service.