在做一个显示当前顶部activity名和包名的ToolApp时遇到的问题。

在Android5.0之前,获取top Activity方法非常简单。直接使用getRunningTasks方法即可。

        //getRunningTasks() is deprecated since API Level 21 (Android 5.0)          List localList = manager.getRunningTasks(1);          ActivityManager.RunningTaskInfo localRunningTaskInfo = (ActivityManager.RunningTaskInfo)localList.get(0);          info.packageName = localRunningTaskInfo.topActivity.getPackageName();          info.topActivityName = localRunningTaskInfo.topActivity.getClassName();  

但是这个方法到了5.0就被Android因安全原因ban掉了。这之后使用该方法只能获取到Laucher的信息了。

后来有人找出了ActivityManger的一个方法:

private String getLollipopRecentTask() {     final int PROCESS_STATE_TOP = 2;     try {         Field processStateField = ActivityManager.RunningAppProcessInfo.class.getDeclaredField("processState");         List processes = ((ActivityManager) getSystemService(Context.ACTIVITY_SERVICE)).getRunningAppProcesses();         for (ActivityManager.RunningAppProcessInfo process : processes) {             if (process.importance <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && process.importanceReasonCode == 0) {                 int state = processStateField.getInt(process);                 if (state == PROCESS_STATE_TOP) {                 String[] packname = process.pkgList;                 return packname[0];                 }             }         }     } catch (Exception e) {         throw new RuntimeException(e);     }     return ""; }
然而仅仅过了一个Android OS版本,这个也无法生效了。

所以有人找出了这样的方法:

    public static void getInfo() {        if (Build.VERSION.SDK_INT >= 21) {            if (mUsageStatsManager != null) {                long now = System.currentTimeMillis();                // get app data during 60s                List stats = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_BEST, now - 60 * 1000, now);                // get present app                if ((stats != null) && (!stats.isEmpty())) {                    int j = 0;                    for (int i = 0; i < stats.size(); i++) {                        if (stats.get(i).getLastTimeUsed() > stats.get(j).getLastTimeUsed()) {                            j = i;                        }                    }                    topPackageName = stats.get(j).getPackageName();                    topActivityName = "";                }            }        }

通过UsageStatsManager获取最近一段时间的使用数据,找到最后一次被使用的信息。但是这个方法只能获取到Package名,得不到Activity的名字。

后来在StackOverFlow上看到了这样的做法:(https://stackoverflow.com/questions/31980976/get-top-activity-name-in-android-l)

while (true) {    final long INTERVAL = 1000;    final long end = System.currentTimeMillis();    final long begin = end - INTERVAL;    final UsageEvents usageEvents = manager.queryEvents(begin, end);    while (usageEvents.hasNextEvent()) {        UsageEvents.Event event = new UsageEvents.Event();        usageEvents.getNextEvent(event);        if (event.getEventType() == UsageEvents.Event.MOVE_TO_FOREGROUND) {            Log.d("event", "timestamp : " + event.getTimeStamp());            Log.d("event", "package name : " + event.getPackageName());            Log.d("event", "class name : " + event.getClassName());        }    }    try {        Thread.sleep(1000);    } catch (InterruptedException e) {        e.printStackTrace();    }}

似乎可以生效没有试过。但是需要死循环不停地读,没有办法动态地监听,吃相有些难看,不够优雅。

最后通过翻阅资料,找到了一个极佳的方法,就是借助Accessibility辅助功能来实现。

public class WindowChangeDetectingService extends AccessibilityService {    private static final String TAG = "WCDService";    @Override    public void onCreate() {        Log.d(TAG, "onCreate");    }    @Override    public void onDestroy() {        Log.d(TAG, "onDestroy");    }    @Override    protected void onServiceConnected() {        Log.d(TAG, "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;        // Just in case this helps        config.flags = AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;        setServiceInfo(config);    }    @Override    public void onAccessibilityEvent(AccessibilityEvent event) {        Log.d(TAG, "onAccessibilityEvent");        if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {            if (event.getPackageName() != null && event.getClassName() != null) {                ComponentName componentName = new ComponentName(                        event.getPackageName().toString(),                        event.getClassName().toString()                );                ActivityInfo activityInfo = tryGetActivity(componentName);                boolean isActivity = activityInfo != null;                if (isActivity) {                    Log.d(TAG, "CurentActivity " + componentName.flattenToShortString());                    ActivityManagerUtils.topActivityName = componentName.flattenToShortString();                    ActivityManagerUtils.topPackageName = event.getPackageName().toString();                }            }        }    }    private ActivityInfo tryGetActivity(ComponentName componentName) {        try {            return getPackageManager().getActivityInfo(componentName, 0);        } catch (PackageManager.NameNotFoundException e) {            return null;        }    }    @Override    public void onInterrupt() {}}

需要一个继承Accessbility的Service,在它的onAccessbilityEvent回调方法里监听到窗口状态改变的事件,从中获取Activity的信息。

需要在AndroidManifest里面配置:

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

这个Service不需要自己手动启动,只要在手机的Setiings Accessbility里面打开注册了这个Service的APP对应的Accessbility的功能,这个Service就会自动启动。


附:我自己做的显示当前页面Activity信息的APP,CurrentActivity。

GitHub:   https://github.com/Haocxx/CurrentActivity


更多相关文章

  1. Android兼容性问题 -- SparseArray.clone()方法异常
  2. Android Studio:xxx is not an enclosing class 错误的解决方法
  3. Android logcat内核信息
  4. 【Android】Android 发送短信和打电话的方法
  5. Android中AutoCompleteTextView的特殊使用方法
  6. Android 解决fragment replace方法低效的问题
  7. Android中WARNING: Application does not specify an API level
  8. 使用android中的handler延迟执行方法

随机推荐

  1. [每天学点Android开发]Building Web Apps
  2. Android P SystemUI之StatusBar加载流程
  3. android > 禁止横竖屏切换
  4. Android中丰富多彩的onTouch事件
  5. [Android]解决控件重叠、覆盖的问题
  6. Android图像处理
  7. android布局ui
  8. Android:EditText 常用属性
  9. ubuntu下无法更新android sdk
  10. 四、 Android之手机屏幕朝向