I want to play my own custom notification sound to set my app apart from a system default sound. So, when I receive a GCM message, I have a function called generateNotification that puts a notification in the status bar and plays a sound.
Currently, I set the path to the sound like this:
String GENERAL_NOTIFICATION_SOUND = "android.resource://" + MyActivity.getInstance().getPackageName() + "/" + R.raw.sound_file;
This works when the app is open, even when the app is recently closed. But if the app is closed by Android's memory management, then MyActivity.getInstance() returns null, and my app crashes with a NullPointerException without properly displaying a notification because it couldn't resolve the path.
I believe I could just fix this by hardcoding the path, but I feel like there has to be a better way. How can you set a path to files that need to be accessed when the app might not be open?
First, you should not have a MyActivity.getInstance(), as that is a memory leak.
Second, whatever code is raising the Notification already has access to a Context, as that is where you get a NotificationManager from. getPackageName() is a method on Context. So, for example, your GCM IntentService is a Context, and so not only can it use getSystemService() to retrieve a NotificationManager, but it can call getPackageName() on itself to find out your app's package name.
Related
This question already has answers here:
How to get the sender of an Intent?
(8 answers)
Closed 3 years ago.
Is there a way to find out, if my Android App was opened by the launcher or by some third party app?
Something like this maybe?
click
I am trying to build an app that can toggle torch. Which already works (I am new to Java and Android). But I want Bixby Button on my Samsung phone to open the app and then toggle torch automatically. Bixby is able to open a app since the newest version.
I found out, that if I open the app from the launcher and resume, it's the same instance. But if Bixby opens the app, it seems to be a new instance every time.
And I don't want to use Availability Service to receive bixby button event.
kind regards
#Vladyslav Matviienko, thank you for this link:
This seems to work:
protected void onResume() {
super.onResume();
Uri uri = this.getReferrer();
if (uri==null) textView.append("Host: null");
else textView.append("Host: " + uri.toString());
}
When opened by launcher, uri is "null", but when opened by bixby, it is "android-app://com.samsung.android.bixby.agent"
EDIT: On a second try launcher is "android-app://com.sec.android.app.launcher".
This has been asked a couple of times on Unity Questions, but never answered.
All I need to do is creare an Android pluugin which downloads few files from given urls and show a downloading progress in notification panel. Downloading should continue even if my Unity application is out of focus.
(source: cuelogic.com)
Here is a peice of code that I have right now:
void DownloadFiles(string[] urls)
{
foreach(var url in urls)
{
StartCoroutine(DownloadFile_CR(url));
}
}
IEnumerator DownloadFile_CR(string url)
{
WWW www = new WWW(url);
while(!www.isDone)
{
yield return null;
}
if(www.error == null)
{
//file downloaded. do something...
}
}
These are some texture files. So How do I get the texture result back from native android code?
Any king of help is appreciated.
I had the same problem. At first, I used a service that worked in the background and downloaded the files I needed, including calculating progress and on complete events.
Then, I made my plugin a little more simple and easy to use. You make an instance of a Java object, providing it with the GameObject name and method name for the responses. I used json to serialize and deserialize java and C# objects, because only strings can be passed between Unity's MonoBehaviour objects and java objects.
Here is how the downnload looks in the android plugin:
Uri Download_Uri = Uri.parse(url);
DownloadManager.Request request = new DownloadManager.Request(Download_Uri);
//Restrict the types of networks over which this download may proceed.
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE);
//Set whether this download may proceed over a roaming connection.
request.setAllowedOverRoaming(true);
//Set the local destination for the downloaded file to a path within the application's external files directory
String[] split = url.split("/");
request.setDestinationInExternalFilesDir(activity, null, split[split.length-1]);
//Set the title of this download, to be displayed in notifications (if enabled).
request.setTitle("Downloading " + title);
//Set a description of this download, to be displayed in notifications (if enabled)
request.setDescription("Downloading " + name);
request.setVisibleInDownloadsUi(false);
//Enqueue a new download and get the reference Id
long downloadReference = downloadManager.enqueue(request);
Then you could send back to unity the reference Id so you can get the progress and check if a file is still downloading once your app is been restarted (use SharedPreferences \ PlayerPrefs to store them)
If you want it to continue even when unity is not in focus then you cannot do it in C# in Unity with the WWW class.
If i wanted to do this i would probably write a native Android plugin that starts a download service.
From the official google docs:
A Service is an application component that can perform long-running
operations in the background, and it does not provide a user
interface. Another application component can start a service, and it
continues to run in the background even if the user switches to
another application.
Services are not that complex, you start them with Intents just as you would an activity and there are lots of examples online for this type of service.
Here is the official Android documentation regarding services: https://developer.android.com/guide/components/services.html
I have added a local notifications so when my app gets a push while opening there is still a popup and a sound.
It's working fine on Android, but on iOS the local notification doesn't appear at all.
The push notifications are working fine on both platforms.
This is my code in the push callback that should trigger the notification (if the app is open):
if(Display.getInstance().getCurrent() != null) {
LocalNotification n = new LocalNotification();
n.setId(value);
n.setAlertBody(value);
n.setAlertTitle({app name});
n.setBadgeNumber(1);
Display.getInstance().scheduleLocalNotification(n, System.currentTimeMillis() + 1000, LocalNotification.REPEAT_NONE);
}
Local notifications don't fire while the app is open in the foreground. You should use a different mechanism to make a sound while the app is running. Eg Display.vibrate()
- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"DriverNotification" object:nil userInfo:userInfo];
// [[NSNotificationCenter defaultCenter] postNotificationName:#"UserNotification" object:nil userInfo:userInfo];
NSLog(#"%#",userInfo);
}
Put This Code in Your View Controller
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receiveNotification:) name:#"DriverNotification" object:nil
];
Did you call registerUserNotificationSettings to register the fact that your app uses local notifications? If you don't do that, your request to post a local notification will be ignored.
See this text from the description of that method:
If your app displays alerts, play sounds, or badges its icon, you must
call this method during your launch cycle to request permission to
alert the user in these ways. (You must also make this request if you
want to set the applicationIconBadgeNumber property directly.)
Typically, you make this request if your app uses local or remote
notifications to alert the user to new information involving your app.
The first time your app launches and calls this method, the system
asks the user whether your app should be allowed to deliver
notifications and stores the response. Thereafter, the system uses the
stored response to determine the actual types of notifications you may
use.
After calling this method, the app calls the
application:didRegisterUserNotificationSettings: method of its app
delegate to report the results. You can use that method to determine
if your request was granted or denied by the user.
It is recommended that you call this method before you schedule any
local notifications or register with the push notification service.
Calling this method with a new user settings object replaces the
previous settings request. Apps that support custom actions must
include all of their supported actions in the notificationSettings
object.
you need to add below code in didFinishLaunchingWithOptions method of AppDelegate.m file for register local notification
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if ([[UIApplication sharedApplication] respondsToSelector:#selector(registerUserNotificationSettings:)])
{
[[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
else
{
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
(UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert)];
}
}
I am working on a phonegap application, with some native pieces.
So far I have notifications running natively, to make sure javascript and phonegap is not required at all. The problem I am having however, is when the notification is clicked I'd like to open the app, or otherwise just bring the app to the front.
How do I do this? I tried setting the main activity in the intent, but it restarts my application every time.
Intent notificationIntent = new Intent(context, main.app.class);
notificationIntent.putExtra(NOTIF_RESPOND, runThis);
notificationIntent.setAction(Intent.ACTION_VIEW);
notificationIntent = notificationIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
Actually in Android there is almost no such thing as "restarting application". Basically the Application - is a bundle of all your services/activities/providers etc. It's either running or not.
If user starts a new Activity - system will check, if application is running - it will create this activity inside the application. If no - will create new Application instance.
So I think you mean that if you set intent for your Main activity - another instance of Activity is launching, am I right?
If so - take a look at the following flag for activity, you should try to set in in the Manifest(or whatever in PhoneGap, sorry). http://developer.android.com/guide/topics/manifest/activity-element.html#lmode
<activity android:name=".YourActivity"
android:launchMode="singleTask"
...
This flag will tell the system not to create a new Activity each type it will be needed, but to reuse already-existing one. Be careful, you should properly implement onNewIntent method in this case to handle this "relaunches", and I'm not 100% sure that it's implemented in PhoneGap.
Good luck
I am developing an application where i have file uri as well as bt device address with me. I need to send the file to the defined bt device. But, the device picker screen should not be shown. It should directly start the device sending.
Obviously, intent:ACTION_SEND is not an option here, as it will show the chooser dialog. The main intension of the application is to bypass the chooser dialog and enable user to send selected file to selected device directly.
So, i was trying the following solution suggested in stack-overflow:
/*BluetoothDevice device;
String filePath = Environment.getExternalStorageDirectory().toString() + "/file.jpg";
ContentValues values = new ContentValues();
values.put(BluetoothShare.URI, Uri.fromFile(new File(filePath)).toString());
values.put(BluetoothShare.DESTINATION, device.getAddress());
values.put(BluetoothShare.DIRECTION, BluetoothShare.DIRECTION_OUTBOUND);
Long ts = System.currentTimeMillis();
values.put(BluetoothShare.TIMESTAMP, ts);
Uri contentUri = getContentResolver().insert(BluetoothShare.CONTENT_URI, values);*/
But unfortunately, it is not working. After getContentResolver().insert, there is no action taken. Needless to say, i have tried various permissions and other stuffs, but to no effect.
So, people who have used this code, please provide your suggestions. Any help to meet the requirement will be very much appreciated.
Does it produce any exception? Please share your Logcat output.
By the way, make use you have the following permission in AndroidManifest.xml
<uses-permission android:name="android.permission.BLUETOOTH"/>
If you are doing a device discovery, add this too in the manifest file
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
I also found this problem. I can show some evidence to solve this problem. After trying this code check outbound transfer queue of your device (to open it, Send a file manually to a device and click the notification icon). Then you can see device has tried to send objects and those were failed. Click on one failure message and you can see pop-up with no file path. I think the problem is though here we are setting the file path using URI to the contentValues it will not be checked in the process. We have to do some thing for this.