Check if an app, for example, Instagram is started by user.
Note: My app is targeting lollipop and above versions in android
Yeah the only way you can do it is through the Accessibility Service. Look at this page to understand how to create it. https://developer.android.com/training/accessibility/service.html They will also need to enable the service via the services -> accessibility screen.
AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED you can probably interrogate the package in front to figure out if Instigram is on top.
You definitely don't want to use getRunningTasks since the function was modified in Android 5.0+
I figured out that I can do this by using usage access feature.
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public static String getForegroundProcess(Context context) {
String topPackageName = null;
UsageStatsManager usage = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
long time = System.currentTimeMillis();
List<UsageStats> stats = usage.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000*1000, time);
if (stats != null) {
SortedMap<Long, UsageStats> runningTask = new TreeMap<Long,UsageStats>();
for (UsageStats usageStats : stats) {
runningTask.put(usageStats.getLastTimeUsed(), usageStats);
}
if (runningTask.isEmpty()) {
return null;
}
topPackageName = runningTask.get(runningTask.lastKey()).getPackageName();
}
if(topPackageName==null) {
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
context.startActivity(intent);
}
return topPackageName;
}
Now continuously check if the desired app is in the foreground.
String fg=getForegroundProcess(getApplicationContext());
if(fg != null && fg.contains("com.instagram.android")){
//Instagram is in foreground
}else {
}
I continuously run the above code with a job service.Which is available for
lollipop and above.
Related
I am trying to build a parental control app. So now i want to disable or lock app (like Whatsapp, Facebook, etc). I have tried using PackageManager.setComponentEnabledSetting(). But it is throwing java.lang.SercurityException.
So how can I make a parental control app such that I can disable any app I want without root.
my code is
pm.setComponentEnabledSetting(new ComponentName(temp.activityInfo.packageName,
temp.activityInfo.name+".class"),
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
my error was this
java.lang.SecurityException: Permission Denial: attempt to change component state from pid=11537, uid=10067, package uid=10029
You must add below permissions to manifest.
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
but , these permissions are for System apps and you can not use. :(
You can not write a app to lock or close another app.this is a policy in Google.
for lock a app you must check running apps repeatedly, if specific app is open,then show a activity over that.
while(!Thread.currentThread().isInterrupted())
{
String topActivity = getFrontApp();
if(topActivity.isEmpty())
{
threadSleep(500);
continue;
}
if(topActivity.equals("lockApp"))
{
showLockActivity();
}
threadSleep(500);
}
// for Api21+ need permission
public static String getFrontApp()
{
if (Build.VERSION.SDK_INT >= 21)
{
UsageStatsManager usageManager = SystemMaster.getUsageStatsManager();
long now = System.currentTimeMillis();
List<UsageStats> localList = usageManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, now - 900_000L, now);
String str = "";
if (localList != null)
{
SortedMap<Long,UsageStats> mySortedMap = new TreeMap<>();
for(UsageStats usageStats : localList)
mySortedMap.put(usageStats.getLastTimeUsed(), usageStats);
if(!mySortedMap.isEmpty())
str = mySortedMap.get(mySortedMap.lastKey()).getPackageName();
}
return str;
}
else
{
ActivityManager am = (ActivityManager) getApplication().getSystemService(Context.ACTIVITY_SERVICE);
return am.getRunningTasks(1).get(0).topActivity.getPackageName();
}
above code is very simple , for real app must write more.
Forgive me if this question was already asked, I couldn't find an answer for my case.
So, I have an Android app with Voice & Video call feature. I used webRTC for this.
I was able to make both Voice and Video call working perfectly inside an Activity, but now I want to keep the call running while the user exit the CallActivity and go back to the ChatActivity (to send a file/link/photo for example).
I managed to make the Voice call run perfectly inside a Background Service, but video call won't work as expected.
The remote video won't be displayed even though the audio from the video track is playing.
here is my Background Service code :
#Override
public void onAddStream(MediaStream mediaStream) {
if (mediaStream.videoTracks.size() > Constants.ONE || mediaStream.audioTracks.size() > Constants.ONE) {
return;
}
//check for video track, means this is a video call
if (!isAudioCall && mediaStream.videoTracks.size() > Constants.ZERO) {
remoteVideoTrack = mediaStream.videoTracks.get(Constants.ZERO);
CallActivityNew.remoteVideoTrack = remoteVideoTrack;
try {
localAudioTrack.setEnabled(true);
//Now ask the UI to display the video track
sendOrderToActivity(Constants.START_REMOTE_VIDEO, null);
} catch (Exception ignored) {}
} else if (mediaStream.audioTracks.size() > Constants.ZERO) {
//Means this is a Voice call, only audio tracks available
remoteAudioTrack = mediaStream.audioTracks.get(Constants.ZERO);
try {
localAudioTrack.setEnabled(true);
remoteAudioTrack.setEnabled(true);
} catch (Exception ignored) {}
}
}
and below my CallActivity code :
case Constants.START_REMOTE_VIDEO: {
if (remoteVideoView == null) {
remoteVideoView = findViewById(R.id.remote_gl_surface_view);
}
remoteVideoView.init(eglBaseContext, null);
remoteVideoView.setEnableHardwareScaler(true);
remoteVideoView.setMirror(true);
remoteVideoView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT);
remoteVideoView.setZOrderMediaOverlay(true);
//Apply video track to the Surface View in order to display it
remoteVideoTrack.addSink(remoteVideoView);
//now enable local video track
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
//now enable local video track
remoteVideoTrack.setEnabled(true);
}
}, Constants.TIME_THREE_HUNDRED_MILLIS);
setSpeakerphoneOn(false);
break;
}
I am sending orders from Service to Activity, the "case Constants.START_REMOTE_VIDEO" work after receiving the order from Service.
I don't see where the problem, why am I only hearing sound but the remote video won't start display !!
Thank you in advance for helping.
After testing for long hours, I found that my code works just fine, I just forget to change the view visibility from "GONE" to "VISIBLE".
Yeah that was the solution, i swear xD
I'm making a game in Unity for Android. I have implemented a notification system. Notifications show and clicking on them opens the game. The thing I'm stuck on is how to know if the game/app is launched by tapping the notification?
Here is the java code for the notification plugin I'm using https://github.com/GoShikhar/unity-android-notifications/blob/master/PluginSrc/app/src/main/java/net/agasper/unitynotification/UnityNotificationManager.java
This is my manifest https://github.com/GoShikhar/unity-android-notifications/blob/master/UnityProject/Assets/Plugins/Android/AndroidManifest.xml
In my unity start scene I use this to check for intent messages.
void Start(){
AndroidJavaClass unityPlayerClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
var activityObject = unityPlayerClass.GetStatic<AndroidJavaObject>("currentActivity");
AndroidJavaObject intent = activityObject.Call<AndroidJavaObject>("getIntent");
int NotificationID = intent.Call<int>("getIntExtra", "id", -1);
print("NOTIFDICATION ID " + NotificationID);
bool hasExtra = intent.Call<bool>("hasExtra", "arguments");
string arguments = null;
if (hasExtra)
{
AndroidJavaObject extras = intent.Call<AndroidJavaObject>("getExtras");
arguments = extras.Call<string>("getString", "title");
print("title : " + arguments);
arguments = extras.Call<string>("getString", "message");
print("message: " + arguments);
}
if (arguments != null)
{
print("App opened via notification");
}
}
This not working. The default notification ID is being printed i.e. -1. Also title and message are null. Even though the notification has the title and message parameter.
I have seen lots of examples for Android Studio but not for Unity. So any help will be appreciated.
Thanks in advance.
Do you mean deep linking? Perhaps this Github project would be helpful: https://github.com/TROPHiT/UnityDeeplinks.
I have a small functionality. Switching on the torch and keeping it on, till the user switches it off from my app or my app exits. Using :
params = camera.getParameters();
if (params.getFlashMode().equals(Parameters.FLASH_MODE_TORCH)) {
isFlashOn = true;
return;
}
params.setFlashMode(Parameters.FLASH_MODE_TORCH);
camera.setParameters(params);
camera.startPreview();
And to switch off :
if (params.getFlashMode().equals(Parameters.FLASH_MODE_OFF)) {
isFlashOn = false;
return;
}
params.setFlashMode(Parameters.FLASH_MODE_OFF);
camera.setParameters(params);
camera.stopPreview();
But I notice that this is not very robust. Works fine the first time, but after that (especially on my API levle 22 phone) might not work. I was thinking of testing with the android.hardware.camera2 as suggested here
Plan to use if (android.os.Build.VERSION.SDK_INT >20) and a strategy (a base interface implemented by two classes, one using old API and one the new camera2 API.
Is this safe on all devices? I saw that we can do it for android classes, but is it okay for our own classes too? Or are there devices which scan all our code and reject it if it has code that refers to API it does not know about?
I do not want to make two APKs as its a small functionality.
I make sure flash is available like this , not tested on all devices but in an emulator by Genymotion app did not crash.
public boolean torchInit() {
try {
PackageManager pm = app.getPackageManager();
// First check if device supports flashlight
boolean hasFlash = pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH);
if (!hasFlash) {
Toast.makeText(app, "Flash not found or can\'t get hold of it. No torch", Toast.LENGTH_LONG).show();
return false;
}
camera = Camera.open();
Camera.Parameters params = camera.getParameters();
Log.i(LogId, "camera params flash: " + params.getFlashMode());
return true;
} catch (Throwable e) {
Log.e(LogId, "cameraFlashSetup " + e, e);
Toast.makeText(app, "Flash error, no torch. Description : " + e, Toast.LENGTH_LONG).show();
camera = null;
}
return false;
}
The flash interface to change between the two classes is :
public abstract class TorchInterface {
protected AppCompatActivity app;
public void init(AppCompatActivity ap){
app = ap;
}
public abstract boolean torchInit();
public boolean torchReInit(){
return torchInit();//if re init is not different than init
}
public abstract boolean torchOn();
public abstract boolean torchOff();
}
Update: new code worked but only if I:
mBuilder = camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
Instead of:
mBuilder = camera.createCaptureRequest(CameraDevice.TEMPLATE_MANUAL);
But then switches on flash as soon as init the app. I was going to chuck it, then realised on my Camera2Impl I can :
public boolean torchInit() {
//do nothing on usual init that app calls on create
return true;
}
And instead do the init on torch on (flash on):
public boolean torchOn() {
//if not in it, try first 3 times
if(mBuilder == null || mSession == null){
if(firstFewTimesTorchOn > 0){
firstFewTimesTorchOn--;
torchInit2();
try{
Thread.sleep(150);
}catch(Exception e){}
if(mBuilder == null || mSession == null) {
return false;
}
}
}
try {
mBuilder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_TORCH);//and etc
Android devices do not "scan" code - compiler does. Therefore, I don't see any issue with your idea. On contrary - using Strategy pattern is way better then if-else all over the code.
Something along these lines should work:
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
mFlashlightStrategy = new PostLollipopStrategy();
} else {
mFlashlightStrategy = new PreLollipopStrategy();
}
Is this safe on all devices?
Why dont't you put one check whether flash is available or not.
context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH);
which will return true if a flash is available, false if not. You can write your further code in true block.
I downloaded apk file from url(my server) and save it in sdcard. If user install it from sdcard, I want to know, whether is any notification that app is installed successfully or is app istalled in device. Is there any callback on installed app
try this code :
protected boolean isAppInstalled(String packageName) {
Intent mIntent = getPackageManager().getLaunchIntentForPackage(packageName);
if (mIntent != null) {
return true;
}
else {
return false;
}
}
to get the package name of the app easily : just search your app in the google play website , and then you will take the id parameter ( it is the package name of the app) . Example :
you will search on Youtube app on google play , and you will find it in this url :
https://play.google.com/store/apps/details?id=com.google.android.youtube&feature=search_result#?t=W251bGwsMSwxLDEsImNvbS5nb29nbGUuYW5kcm9pZC55b3V0dWJlIl0.
the package name is the id param, so it is : com.google.android.youtube
And then when you want to test , you will just have :
String packageName = "com.google.android.youtube";
boolean isYoutubeInstalled = isAppInstalled(packageName);
PLUS : if you want to get the list of all installed apps in you device , you can find your answer in this tutorial
final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
final List pkgAppsList = context.getPackageManager().queryIntentActivities( mainIntent, 0);
You'll get the list of all installed applications on Android.
Use this to check if an application is installed
PackageManager pm = context.getPackageManager();
List<ApplicationInfo> list = pm.getInstalledApplications(0);
for (int i = 0; i < list.size(); i++) {
if(list.get(i).packageName.equals("com.my package")){
//do what you want
}
}
In Youtube Player API, you can access YoutubeIntents class and use isYoutubeInstalled to verify if device has the Android app or not.