I have the following code:
https://github.com/lucas-kejan/React-Widget/blob/master/android/app/src/main/java/com/androidwidgetpoc/BackgroundTaskBridge.java#L26
That should add the widget to the android home screen, when the method is called, but it does not work.
It gives me the following error:
lenght = 0; index = 0.
BackgroundTaskBridge.java:31
Well, let's take a look on things that you want to do - let user to pick widget and take a place in launcher. If you want to make it pre Oreo devices, where is no api for following action. So to run PICK_APPWIDGET intent you need appWidgetId. The only way to get appWidgetId by yourself is to bind id to appWidgetInfo, but this thing requires BIND_APPWIDGET permission, which is only available to system. So on pre Oreo device it's impossible to make a thing that you want (of course if you're not a system app).
On Oreo devices we have a new pinning widget api.
AppWidgetManager mAppWidgetManager =
context.getSystemService(AppWidgetManager.class);
AppWidgetProviderInfo myWidgetProviderInfo = new AppWidgetProviderInfo();
ComponentName myProvider = myWidgetProviderInfo.provider;
if (mAppWidgetManager.isRequestPinAppWidgetSupported()) {
// Create the PendingIntent object only if your app needs to be notified
// that the user allowed the widget to be pinned. Note that, if the pinning
// operation fails, your app isn't notified.
Intent pinnedWidgetCallbackIntent = new Intent( ... );
// Configure the intent so that your app's broadcast receiver gets
// the callback successfully. This callback receives the ID of the
// newly-pinned widget (EXTRA_APPWIDGET_ID).
PendingIntent successCallback = PendingIntent.createBroadcast(context, 0,
pinnedWidgetCallbackIntent);
mAppWidgetManager.requestPinAppWidget(myProvider, null,
successCallback.getIntentSender());
}
Don't forget that it requires api version 26+. You can check documentation of following api here
Related
The problem seems to be known, but I could not find the right solution.
I will describe the scenario:
There is an application making requests to the API. In some FirstActivity, a request is made to the API, upon positive result of which startActivity () is called in SecondActivity. The problem is that if, while sending the request, the application is minimized to the background (that is, startActivity () will be called in the background), then:
If android version> = 29 then startActivity () basically won't work. The one following startActivity () finish () will work and upon restarting the application will restart (which is logical)
If the android version is < 29, then startActivity () will fire and bring this SecondActivity to the foreground.
Based on this, the question is. How can I force the application, regardless of version, to transition between activities and not bring them to the front?
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);
finish();
As per documentation
Android 10 (API level 29) and higher place restrictions on when apps
can start activities when the app is running in the background.
Workaround : In specific situations, your app might need to get the user's attention urgently, such as an ongoing alarm or incoming call. You might have previously configured your app for this purpose by launching an activity while your app was in the background.
To provide similar behavior on a device running Android 10 (API level 29) or higher, complete the steps described in this guide.
you can show a high-priority notification with a full-screen intent.
More Details
Updated answer for new requirement: For your comment
(Well, please tell me how to make startActivity () in the background start the activity also in the background, and not raise the application from the background)
you can add a LifecycleObserver that will be notified when the LifecycleOwner changes state.
Inside your activity api response callback use the following condition
if (lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) {
// Activity is in resumed state, Open new activity immediately
} else {
// else add a LifecycleObserver that will be notified when the LifecycleOwner changes state
lifecycle.addObserver(object : DefaultLifecycleObserver {
override fun onStart(owner: LifecycleOwner) {
super.onStart(owner)
// remove observer immediately so that it will not get triggered all the time
lifecycle.removeObserver(this)
// Activity is in start state again, Open new activity here
}
})
}
I am using Firebase (FCM) to show Push Notifications to the user and I am running into a weird problem.
The code I have works for the following scenarios (using FirebaseMessagingService):
App in foreground - Receiving data in onReceive() and showing a popup inside app.
App in background - Receiving data in onReceive() and showing a notification for the user. If this is clicked the app will be brought back to front. The intent from this is received in LauncherActivity followed by a finish() call which takes me to whatever activity I already had open.
App completely closed - same as background. App will be started and intent will be handled in LauncherActivity before calling finish() on that.
And here is where it gets interesting:
App completely closed -> open it through notification (intent received in LauncherActivity) -> put the app in background and send another notification -> when this notification is clicked the LauncherActivity is completely ignored (onCreate is no longer called) and I get taken straight to whatever activity I already had. The intent here has no extras or categories.
Why is LauncherActivity being bypassed in this specific case? Keep in mind that this works fine if the app was initially started normally (not by clicking on a notification)
Intent mainIntent = getPackageManager().getLaunchIntentForPackage(getPackageName());
if (mainIntent != null) {
mainIntent.addCategory(NOTIFICATION_CATEGORY);
mainIntent.putExtra(.........);
}
PendingIntent pendingMainIntent = PendingIntent.getActivity(this, SERVICE_NOTIFICATION_ID, mainIntent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, context.getString(R.string.default_notification_channel_id));
notificationBuilder.setContentIntent(pendingMainIntent);
//.....icon, color, pririty, autoCancel, setDefaults, setWhen, setShowWhen, contentText, setStyle
NotificationManager notificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
getString(R.string.default_notification_channel_id),
getString(R.string.default_notification_channel),
NotificationManager.IMPORTANCE_HIGH
);
notificationManager.createNotificationChannel(channel);
notificationBuilder.setChannelId(getString(R.string.default_notification_channel_id));
}
notificationManager.notify(SERVICE_NOTIFICATION_ID, notificationBuilder.build());
}
I'd appreciate any ideas. Thank you.
When you launch an app for the first time, Android remembers the Intent that was used to launch it. Normally, when you launch an app from the HOME screen, this is an Intent that contains ACTION=MAIN and CATEGORY=LAUNCHER. If your app then goes to the background (for whatever reason), and the user later taps the icon on the HOME screen, the same launch Intent is used. Android matches this against the Intent used to launch the app for the first time, and if these match, Android doesn't launch a new Activity, it just brings the task containing the app from the background to the foreground in whatever state it was in when it got moved to the background. Under normal circumstances, this is exactly the behaviour that you want (and that the user expects).
However, when the app is launched for the first time from a Notification, this can mess things up. In your case, this is what you are seeing. You launch the app from a Notification and Android remembers the Intent used (from the Notification), when you later launch the app (again from a Notification), android matches the Intent in the Notification with the Intent used to launch the app for the first time, and thinks you want to bring the existing app task from the background to the foreground.
There are several ways to deal with this, depending on the behaviour that you want to have. The best thing to do is probably not to launch your root Activity (the one with ACTION=MAIN and CATEGORY=LAUNCHER) from the Notification. Instead launch a different Activity and have that Activity determine what it should do next (ie: redirect to the root Activity or something else, depending on the state of your app). You should also set the NO_HISTORY and EXCLUDE_FROM_RECENTS flags on the Intent that you put in the Notification. This will ensure that Android won't remember this Intent as the one that launched the app.
I have created a custom ui and making a call using telecom manager for direct dialing. But every time Device default Calling UI is opening.
Here is some code for making calls directly...
TelecomManager telecomManager=(TelecomManager)getSystemService(Context.TELECOM_SERVICE);
Uri uri = Uri.fromParts("tel", phonenumber, null);
Bundle extras = new Bundle();
extras.putBoolean(TelecomManager.METADATA_IN_CALL_SERVICE_UI, true);
extras.putBoolean(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,true);
try {
if (telecomManager!=null) {
telecomManager.showInCallScreen(true);
}
}catch(SecurityException incoming){
incoming.printStackTrace();
}
try {
if (telecomManager!=null) {
telecomManager.placeCall(uri, extras);
}
}catch(SecurityException unlikely){
unlikely.printStackTrace();
}
is there a way to hide the default calling ui and use our own calling ui.?
Any help will be appreciated.
See the API docs on how to use the placeCall API. METADATA_IN_CALL_SERVICE_UI should not be passed to placeCall, and EXTRA_PHONE_ACCOUNT_HANDLE is not a boolean extra. You need to pass in a PhoneAccountHandle. However, if you're just trying to place a regular mobile call, just omit that extra as the system will pick the right one.
showInCallScreen should also only really be used by the Dialer app to bring its UI to the foreground; its not going to have any impact in your case.
If you want to use your Dialer app as the in-call UI, you need to change it in the system settings.
System Settings --> Apps & Notifications --> Advanced --> Default Apps --> Phone App. Choose your app there.
To be a default phone app you need to handle the DIAL intent and implement the InCallService API.
My Activityhosts 3 tabs and each tab is a Fragment.
I also have a Service which query a database perdiodically. Depending on the result of the query, I raise a Notification (from the Service).
When I click on the Notification, is it possible to launch a specific fragment? If yes, how can I do so?
Here is what I've done so far, in my Service class:
// When notification is clicked, go back to TabOperations Fragment
Intent i = new Intent(this, TabOperations.class);
PendingIntent pi = PendingIntent.getActivity(this, 0, i,PendingIntent.FLAG_UPDATE_CURRENT); // Give the phone access to the app
notification.setContentIntent(pi);
// Issue notification
NotificationManager nm = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
nm.notify(UNIQUE_ID, notification.build());
Of course, this does not work.
Any advice?
Instead of the Service sending a Notification, perhaps you would be better off with a different messaging system. For example, you can utilize the Observer pattern (or third-party libraries like EventBus) to send a message from the Service to the Activity that cares about such events. The activity can then use the event to start and attach the Fragment as necessary.
I am working on an Android application in which I have to compare current time , with a time (saved) in a file, though everything is working fine. I have use services and in service i have use THREAD to run the service infinitely, and in addition to this i have also used PARTIAL_WAKE_LOCK to continue service even the device is sleep but the issue is that instead of acquiring PARTIAL_WAKE_LOCK my service runs for 1/2 hours and then again go to sleep. I don't want to acquire FULL_WAKE_LOCK. Is there any one who can guide me what i have to do in order to run this comparison, i.e. my service will run perfectly once the user set the time.
Thank you in advance.
You are doing it the wrong way. To create permanent service you must
declare it as foreground. No other way about it:
myService.startForeground(MY_NOTIFICATION_ID, my_notification);
If your interest with such a service is to periodically perform fast-ending
actions, and if the in between periods are long, you probably want to use
the alarm API and improve your app's battery consumption.
Edit:
To set a foreground service you must supply the system with a notification
object to be displayed at notification bar for as long as the service is in foreground
Why is that? Because foreground services cannot be killed, and Android needs to know
that the user is aware of that fact.
Setting as foreground:
static final int NOTIF_ID = 100;
// Create the FG service intent
Intent intent = new Intent(getApplicationContext(), MyActivity.class); // set notification activity
showTaskIntent.setAction(Intent.ACTION_MAIN);
showTaskIntent.addCategory(Intent.CATEGORY_LAUNCHER);
showTaskIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pIntent = PendingIntent.getActivity(
getApplicationContext(),
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT);
Notification notif = new Notification.Builder(getApplicationContext())
.setContentTitle(getString(R.string.app_name))
.setContentText(contentText)
.setSmallIcon(R.drawable.ic_notification)
.setContentIntent(pIntent)
.build();
startForeground(NOTIF_ID, notif);
And reverting to 'stardard' service mode:
stopForeground(true).
Both setting to foreground and reverting to background can be called by either the service itself (e.g. its onCreate() method) or by external code (e.g. the activity that initiated the service). No problems here.