Start app over "Always on Display" and lock screen - java

I have an app, that starts on it's own, if it recieves a message.
For this I use this start parameter:
BackgroundService.java:
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD)
.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED)
.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON)
.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
startActivity(intent);
MainActivity.java --> onCreate:
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
Now I received from a user of my app a message, that this is not working with his "Samsung Galaxy S7", and he noticed, that he uses the "Always On Display" function.
I searched for a while in the Web, but I doesn't find a solution.
Are there some more "Tags" to add?

I ran in a similar problem. The flags that you add to the Intent are not meant for an Intent, but for a Window - there is no need to add them there.. You use them correctly in the onCreate(). But the issue is not due to flags.
In my case the problem was that the Activity I was trying to launch uses a Theme, that has <item name="android:windowIsFloating">true</item> in it. I reworked my logic, so I don't have to use it.
Another workaround that works if you absolutely must use the "android:windowIsFloating" is to use
PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
screenWakeLock = powerManager.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.SCREEN_DIM_WAKE_LOCK, "TEST");
and then you can call
screenWakeLock.acquire(5000);
before you set the flags. You can edit the timeout of course.
This is a bit of a hack, because PowerManager.SCREEN_DIM_WAKE_LOCK is deprecated. But it does work on Samsung with Android 8.0 and Samsung Experience Version 9.0.
The whole thing is clearly some Samsung issue, because the same code, without the workarounds works like a charm with Pixel Ambient display with Always on.

Related

How do I launch a specific (explicit) activity of another app

I want to launch a specific activity of another app from my app. For example, on the onCreate of my app, I want to launch the activity named Rolling (not main) activity of com.pas.webcam.pro. I have heard that you must have control of both apps to do this because you must add an intent filter to the manifest of the second app. This is not true though, because activity launcher apps in the Google Play Store can launch the Rolling Activity of IP Webcam Pro.
The Activity Launcher app is open source, so I tried reviewing the source code here. It was too complicated though, so I could not figure out how this app magically launches this activity. There are many other questions like this on Stack Overflow, and I have read every one. I have also tried lots of the code from the answers too, like this:
Intent intent = new Intent(); intent.setComponent(new ComponentName("com.pas.webcam", "com.pas.webcam.RollingActivity")); startActivity(intent);
I have also tried variants of this code from other posts. My app always crashes and I get variants (depending on the code I use) of the following error:
An error occurred
Invalid intent operation. Unable to find explicit activity class {com.pas.webcam.pro/com.pas.webcam.pro.Rolling}; have you declared this activity in your AndroidManifest.xml?
I have put both of the following in my Android Manifest and the same thing happens:
<uses-permission android:name="android.permission.GET_INSTALLED_PACKAGES" />
<activity android:name="com.pas.webcam.pro.RollingActivity"
Thanks in advance for any answers, I really appreciate it, as I have been working on this problem for a while.
Edit: Here is the activity of the app I want to launch: https://i.stack.imgur.com/Fa7Xq.jpg
Edit: David Wasser helped me solve the problem by giving me the code neccessary to solve the problem. It actually works! To anyone who wants to launch a specific activity of another app with code, please use this:
Intent intent = new Intent(); intent.setClassName("com.pas.webcam.pro", "com.pas.webcam.Rolling"); startActivity(intent);
You may replace com.pas.webcam.pro and Rolling with the app and activity of your choice, but this method truly works. Problem Solved!😀
Try this:
Intent intent = new Intent();
intent.setClassName("com.pas.webcam.pro", "com.pas.webcam.Rolling");
startActivity(intent);
Since you refer to the app as "IP webcam pro", I'm assuming the package name is "com.pas.webcam.pro" (found by Internet research).

Programmatically open 'About device' page in Settings correctly?

startActivity(new Intent(android.provider.Settings.ACTION_DEVICE_INFO_SETTINGS)); opens this page in Samsung devices:
However, I want it to open this page like the rest of Android devices, how can I do it?
As Pedro Antonio said:
If it doesn't work for SAMSUNG devices I'm afraid it will probably not be possible. At least with no official answer. Many times vendors modify stock Android so for SAMSUNG devices settings app is different than stock AOSP, and the official method will not work.
When we call:
Intent i = new Intent(Settings.ACTION_DEVICE_INFO_SETTINGS);
startActivity(i);
we are referring to activity com.android.settings.Settings$DeviceInfoSettingsActivity and in logs we can see that activity is started
2020-06-26 11:33:43.804 4838-5126/? I/ActivityManager: START u0 {act=null typ=null flg=0x8000 cmp=ComponentInfo{com.android.settings/com.android.settings.Settings$DeviceInfoSettingsActivity}} from uid 1000
On devices like Huawei P10, Software Information data is part of DeviceInfoSettingsActivity. After some digging i found out that on Samsung S7 device Software Information is Fragment that is called inside DeviceInfoSettingsActivity
2020-06-26 11:44:25.780 7103-9703/? D/Settings: packageName : com.android.settings className : com.android.settings.SubSettings
2020-06-26 11:44:25.812 7103-7103/? D/SubSettings: Launching fragment com.samsung.android.settings.deviceinfo.SoftwareInfoSettings
I am not sure is it possible to access DeviceInfoSettingsActivity code (I couldn't) and see if you can send some extra data to open specific Fragment. So at this point i do not believe that it is possible to launch that specific fragment from intent.
The main point is it seems impossible. Let's look at what is the reason.
The DeviceInfoSettingsActivity can be opened by an intent call like:
Intent intent = new Intent(android.provider.Settings.ACTION_DEVICE_INFO_SETTINGS);
startActivity(intent);
or
Intent intent = new Intent();
intent.setClassName(
"com.android.settings",
"com.android.settings.Settings$DeviceInfoSettingsActivity"
);
startActivity(intent)
As you can see here:
https://android.googlesource.com/platform/packages/apps/Settings/+/master/src/com/android/settings/Settings.java
Settings and all of its inner classes are children of SettingsActivity. By taking a look at source code of SettingsActivity, we found out it is possible to show a sub-settings, passing the fragment name as an intent extra with key ":settings:show_fragment" to the SettingsActivity:
SettingsActivity#onCreate() then SettingsActivity#launchSettingFragment()
If we dig into logs where the target screen is shown, we'd see that the target fragment name is com.samsung.android.settings.deviceinfo.SoftwareInfoSettings.
But the problem is that there is a check on fragment names at SettingsActivity#isValidFragment() which allows specific fragments to navigate to and they are SettingsGateway#ENTRY_FRAGMENTS:
protected boolean isValidFragment(String fragmentName) {
// Almost all fragments are wrapped in this,
// except for a few that have their own activities.
for (int i = 0; i < SettingsGateway.ENTRY_FRAGMENTS.length; i++) {
if (SettingsGateway.ENTRY_FRAGMENTS[i].equals(fragmentName)) return true;
}
return false;
}
The alternative for showing other fragments in settings is to open SubSettings activity which overrides the isValidFragment to accepts every fragment.
#Override
protected boolean isValidFragment(String fragmentName) {
Log.d("SubSettings", "Launching fragment " + fragmentName);
return true;
}
That is exactly what happens when the SoftwareInfoSettings is shown:
D/Settings: packageName : com.android.settings className : com.android.settings.SubSettings
D/SubSettings: Launching fragment com.samsung.android.settings.deviceinfo.SoftwareInfoSettings
Unfortunately, starting the SubSettings from uid except launcher's uid isn't possible, because it is not an exported activity to be visible from the outside:
AndroidManifest.xml:
<activity android:name=".SubSettings"
android:parentActivityName="Settings"
android:theme="#style/Theme.SubSettings"/>
If you try to run:
Intent intent = new Intent();
intent.setClassName(
"com.android.settings",
"com.android.settings.SubSettings"
);
intent.putExtra(
":settings:show_fragment",
"com.samsung.android.settings.deviceinfo.SoftwareInfoSettings"
);
startActivity(intent);
will see this error log:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.aminography.settingsapp, PID: 14566
java.lang.SecurityException: Permission Denial:
starting Intent { flg=0x10000000 cmp=com.android.settings/.SubSettings (has extras) }
from ProcessRecord{fac1d09 14566:com.aminography.settingsapp/u0a104} (pid=14566, uid=10104)
not exported from uid 1000
Unfortunately, since isValidFragment() and SettingsGateway#ENTRY_FRAGMENTS are parts of the platform, not your application's runtime, it's impossible to change them even with reflection.
As the android documentation says, you should use
Intent i = new Intent(Settings.ACTION_DEVICE_INFO_SETTINGS);
startActivity(i);
https://developer.android.com/reference/android/provider/Settings#ACTION_DEVICE_INFO_SETTINGS
If it doesn't work for SAMSUNG devices I'm afraid it will probably not be possible. At least with no official answer. Many times vendors modify stock Android so for SAMSUNG devices settings app is different than stock AOSP, and the official method will not work.

Offline SpeechRecognizer on Android is not working

I am working with SpeechRecognizer. The problem was if there is no active internet connection SpeechRecognizer will throw error SpeechRecognizer.ERROR_NETWORK or SpeechRecognizer.ERROR_SERVER.
This is my RecognizerIntent
final Intent recognizerIntent;
recognizerIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_PREFERENCE, "en");
recognizerIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, this.getPackageName());
recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
recognizerIntent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 5);
recognizerIntent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true);
recognizerIntent.putExtra(RecognizerIntent.EXTRA_PREFER_OFFLINE, true);
And I put recognizerIntent.putExtra(RecognizerIntent.EXTRA_PREFER_OFFLINE, true);
But no luck. again it will throw the same error.
And I got these 2 errors frequently.
SpeechRecognizer.ERROR_RECOGNIZER_BUSY
SpeechRecognizer.ERROR_NO_MATCH
Please help me.
First of all, you need to make sure if you have offline package of language you put to EXTRA_LANGUAGE_PREFERENCE installed on the device.
To enable Offline Speech input in supported devices, follow below steps:
Go to Settings
Click on “Language and input”
On-screen keyboard
Select Google voice typing
Select Offline speech recognition
Install desired language
If it still does not work offline, try to change your EXTRA_LANGUAGE_PREFERENCE value to something more specific, "en-US" for example (That did the trick for me)
And also, if you want to tell SpeechRecognizer wich language it should recognize, I guess you should use EXTRA_LANGUAGE parameter instead of EXTRA_LANGUAGE_PREFERENCE
Hope it will help

How does Facebook add badge numbers on app icon in Android?

I know there are several Qs here that ask if its possible to add badges to an android app and they all end up with a NO answer...
But somehow the latest Facebook beta version for Android seems to do something which at least look like a badge even if it is not technically exactly that.
In that post one of the commenters says that it is somehow related to TouchWiz.
And also here they mention it as a feature of the "S3 TouchWiz Jelly Bean Addon".
I still would appreciate information on how does this can be done and if there is some API for this that I can use in my own app (when running in an appropriate environment - i.e. the same device where FB demonstrates this behavior) ?
Hi you can use this lib simply.
Support : Sony,Samsung,LG,HTC,Xiaomi,ASUS,ADW,APEX,NOVA,Huawei,ZUK,OPPO
ShortcutBadger
Add :
int badgeCount = 1;
ShortcutBadger.applyCount(context, badgeCount);
Remove :
ShortcutBadger.applyCount(context, 0);
I have figured out how this is done for Sony devices.
I've blogged about it here. I've also posted a seperate SO question about this here.
Sony devices use a class named BadgeReciever.
Declare the com.sonyericsson.home.permission.BROADCAST_BADGE permission in your manifest file:
Broadcast an Intent to the BadgeReceiver:
Intent intent = new Intent();
intent.setAction("com.sonyericsson.home.action.UPDATE_BADGE");
intent.putExtra("com.sonyericsson.home.intent.extra.badge.ACTIVITY_NAME", "com.yourdomain.yourapp.MainActivity");
intent.putExtra("com.sonyericsson.home.intent.extra.badge.SHOW_MESSAGE", true);
intent.putExtra("com.sonyericsson.home.intent.extra.badge.MESSAGE", "99");
intent.putExtra("com.sonyericsson.home.intent.extra.badge.PACKAGE_NAME", "com.yourdomain.yourapp");
sendBroadcast(intent);
Done. Once this Intent is broadcast the launcher should show a badge on your application icon.
To remove the badge again, simply send a new broadcast, this time with SHOW_MESSAGE set to false:
intent.putExtra("com.sonyericsson.home.intent.extra.badge.SHOW_MESSAGE", false);
I've excluded details on how I found this to keep the answer short, but it's all available in the blog. Might be an interesting read for someone.
There is not a standard way to achieve this; Many makers such as Sony or Samsung have implemented it in their own Android customization.
For example in Samsung, you have to broadcast an intent with BADGE_COUNT_UPDATE action, let MainActivity be your main activity class and count be the number you want to display in your app icon, note that 0 will hide the badge:
Intent intent = new Intent("android.intent.action.BADGE_COUNT_UPDATE");
intent.putExtra("badge_count", count);
intent.putExtra("badge_count_package_name", context.getPackageName());
intent.putExtra("badge_count_class_name", MainActivity.class.getName());
context.sendBroadcast(intent);
Sony devices uses "com.sonyericsson.home.action.UPDATE_BADGE" action with their custom extras as #Marcus Answered, so you have to add "com.sonyericsson.home.permission.BROADCAST_BADGE" permission to your app manifest and:
Intent intent = new Intent("com.sonyericsson.home.action.UPDATE_BADGE");
intent.putExtra("com.sonyericsson.home.intent.extra.badge.ACTIVITY_NAME", MainActivity.class.getName());
intent.putExtra("com.sonyericsson.home.intent.extra.badge.SHOW_MESSAGE", true);
intent.putExtra("com.sonyericsson.home.intent.extra.badge.MESSAGE", String.valueOf(count));
intent.putExtra("com.sonyericsson.home.intent.extra.badge.PACKAGE_NAME", context.getPackageName());
context.sendBroadcast(intent);
Note: it's desirable to query your app's data (context.getPackageName(), MainActivity.class.getName()) rather than hardcode it just in case you do some refactoring in the future.
But somehow the latest Facebook beta version for android does just that...
Not according to the forum thread that contains the screenshot that you linked to. Quoting vakama94:
Well, that's actually TouchWiz and not just the app. I have a Galaxy S II running JellyBean 4.1.2 and it makes the same thing but with some other applications
Whether Samsung has a public API to allow apps to publish numbers to be used as badges, I cannot say. This could be something that they did privately with a few firms.
You are welcome to provide evidence of seeing these badges on a stock Android home screen, such as one of the Nexus series devices.
I answer to this assuming that some flutter dev can search this...
In Flutter, you can achieve this by using
Flutter app badger library.
It is as simple as
FlutterAppBadger.updateBadgeCount(1); // show
FlutterAppBadger.removeBadge(); // hide

How to add a widget to the Android home screen from my app?

I'm writing an application which should be able to add widgets (just text boxes) to the home screen of the user's phone when the user instructs my app to do so. How can I do such a thing?
I know that I can add an app widget but how about adding more?
It is not possible from a app to place a widget in the home screen. Only the home screen can add app widgets to the home screen.
similar links link1, link2, link3
But you can offer user to pick widget from widgetpicker.
Intent pickIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK);
pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetID);
startActivityForResult(pickIntent, KEY_CODE);
This was answered a long time ago, but in case anyone stumbles upon this question I thought I should provide an up-to-date answer.
As of Android O (API 26), you can now pin widgets to the user's launcher from your app!
Simply create the widget in your app's AndroidManifest file and use AppWidgetManager to request that the widget be pinned to the launcher. Note that it is up to the launcher to support this feature, so you must call AppWidgetManager's isRequestPinAppWidgetSupported() method before requesting to pin it.
Here's some documentation from Google that goes into more detail: https://developer.android.com/preview/features/pinning-shortcuts-widgets.html#widgets
Hope this helps!
Edit: It looks like the documentation pages have changed since I posted this answer. Here is a more helpful link that gives a code example of how to pin a widget to a launcher: https://developer.android.com/guide/topics/appwidgets/#Pinning
Looks like Dalvik Droid's links are updated again, the newest link is at requestPinAppWidget
Example:
in MainActivity.java:
private void requestToPinWidget(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
AppWidgetManager appWidgetManager =
getSystemService(AppWidgetManager.class);
ComponentName myProvider =
new ComponentName(this, AppWidget.class);
assert appWidgetManager != null;
if (appWidgetManager.isRequestPinAppWidgetSupported()) {
Intent pinnedWidgetCallbackIntent = new Intent(this, MainActivity.class);
PendingIntent successCallback = PendingIntent.getBroadcast(this, 0,
pinnedWidgetCallbackIntent, PendingIntent.FLAG_UPDATE_CURRENT);
appWidgetManager.requestPinAppWidget(myProvider, null, successCallback);
}
}
}
Any anywhere in you code you have call requestToPinWidget() to prompt to see if the user wants to add it to the desktop.
Only thing is that this will not add to user's home screen, it will be appended to the page where you see all the apps:
AFAIK default launcher app does not support this. The reason is that user should place everything on the home screen himself. Allowing to place widgets from an application would open doors for apps to "spam" user's home with their "useful" widgets.

Categories

Resources