I'm currently developing an app for tablets which will show commercials in stores. I need to add a password protection for the settings application. To achieve this I need to detect that the settings app is started in a background service. For devices with Android below API 21 this can be done with getRunningTasks(). Unfortunately this method is deprecated now. I tried achieving my goal with this answer, but things aren't working as I need. I'm trying to listen for V/WindowManager( 740): Adding window Window{1f4535ef u0 com.android.settings/com.android.settings.Settings} at 9 of 16 (before Window{e14eed2 u0 Starting com.android.settings})
but I can't see it as an output. I'm using the code from the answer I referenced above. Instead of Toasting it I'm printing it in the logcat.
Can you tell me how my goal can be achieved for android versions above API 21? I know it is possible because apps like Smart AppLock does it. Thanks in advance!
The onPause() and onResume() methods are called when the application is brought to the background and into the foreground again. However, they are also called when the application is started for the first time and before it is killed. You can read more in Activity.
Android 10 (API level 29) and higher place restrictions on when apps can start activities when the app is running in the background. These restrictions help minimize interruptions for the user and keep the user more in control of what's shown on their screen.
Physical activity recognition permission. ACTIVITY_RECOGNITION runtime permission for apps that need to detect the user's step count or classify the user's physical activity, such as walking, biking, or moving in a vehicle. This is designed to give users visibility of how device sensor data is used in Settings.
It currently is not possible to get the foreground app on Android 5.1.1+ unless you are granted the system level permission android.permission.PACKAGE_USAGE_STATS
. Note that several major vendors have removed the system activity that grants access to the UsageStats API from their devices. This means that apps on those devices can never acquire the necessary permission. This may change with a system update.
You mentioned that Smart Lock (App Protector) can detect the current foreground activity on Android M. The first time you open Smart Lock (or similar apps) you are prompted to grant the PACKAGE_USAGE_STATS
permission. So we can conclude that they are relying on UsageStatsManager
to get the foreground application.
I have tried finding a workaround (hack) to get the foreground app on Android M without a system level permission. Please read and try out my script in my answer here: Android 5.1.1 and above - getRunningAppProcesses() returns my application package only
Logcat
Unless you have root permission, reading the logcat to get the foreground application will not work. Reading the logcat since Jelly Bean only returns log messages from your application only.
Useful links:
How to check if "android.permission.PACKAGE_USAGE_STATS" permission is given?
How to use UsageStatsManager?
https://code.google.com/p/android-developer-preview/issues/detail?id=2347
After digging through Android source I wrote the following code to get the foreground app on Android M without any permissions. I have only tested it on a Nexus 9 running the latest developer preview. Please copy and paste the code into a class in your project and test it out by calling the static method getForegroundApp()
:
/** first app user */
public static final int AID_APP = 10000;
/** offset for uid ranges for each user */
public static final int AID_USER = 100000;
public static String getForegroundApp() {
File[] files = new File("/proc").listFiles();
int lowestOomScore = Integer.MAX_VALUE;
String foregroundProcess = null;
for (File file : files) {
if (!file.isDirectory()) {
continue;
}
int pid;
try {
pid = Integer.parseInt(file.getName());
} catch (NumberFormatException e) {
continue;
}
try {
String cgroup = read(String.format("/proc/%d/cgroup", pid));
String[] lines = cgroup.split("\n");
if (lines.length != 2) {
continue;
}
String cpuSubsystem = lines[0];
String cpuaccctSubsystem = lines[1];
if (!cpuaccctSubsystem.endsWith(Integer.toString(pid))) {
// not an application process
continue;
}
if (cpuSubsystem.endsWith("bg_non_interactive")) {
// background policy
continue;
}
String cmdline = read(String.format("/proc/%d/cmdline", pid));
if (cmdline.contains("com.android.systemui")) {
continue;
}
int uid = Integer.parseInt(
cpuaccctSubsystem.split(":")[2].split("/")[1].replace("uid_", ""));
if (uid >= 1000 && uid <= 1038) {
// system process
continue;
}
int appId = uid - AID_APP;
int userId = 0;
// loop until we get the correct user id.
// 100000 is the offset for each user.
while (appId > AID_USER) {
appId -= AID_USER;
userId++;
}
if (appId < 0) {
continue;
}
// u{user_id}_a{app_id} is used on API 17+ for multiple user account support.
// String uidName = String.format("u%d_a%d", userId, appId);
File oomScoreAdj = new File(String.format("/proc/%d/oom_score_adj", pid));
if (oomScoreAdj.canRead()) {
int oomAdj = Integer.parseInt(read(oomScoreAdj.getAbsolutePath()));
if (oomAdj != 0) {
continue;
}
}
int oomscore = Integer.parseInt(read(String.format("/proc/%d/oom_score", pid)));
if (oomscore < lowestOomScore) {
lowestOomScore = oomscore;
foregroundProcess = cmdline;
}
} catch (IOException e) {
e.printStackTrace();
}
}
return foregroundProcess;
}
private static String read(String path) throws IOException {
StringBuilder output = new StringBuilder();
BufferedReader reader = new BufferedReader(new FileReader(path));
output.append(reader.readLine());
for (String line = reader.readLine(); line != null; line = reader.readLine()) {
output.append('\n').append(line);
}
reader.close();
return output.toString();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With