I have an Android app with a PreferenceActivity, and one of the Preference entries launches one of my own activities (the "About" screen). The entry looks like this:
<PreferenceScreen android:title="#string/about.Title">
<intent ... />
</PreferenceScreen>
Also (and this is important), I use Gradle and a .debug application ID suffix for my debug builds. I install both the Play Store version and the debug version on my phone.
The question is: What kind of intent to use above? I know of two options, neither of which work:
Use an android:action intent with my own action string, and register that action string in my manifest with <intent-filter>.
If I use android:exported="false" in the manifest, then the activity fails to load on Android 7.1 when both apps are installed. (I get "Complete action using ... No apps can perform this action".) It works fine if only one is installed (either).
If I use android:exported="true", then not only am I exporting an internal Activity, but when I tap the preference, two instances of the activity are pushed on the stack (one for each app). If I install only one of the two apps, then only one instance shows up.
Use the android:targetPackage and android:androidClass approach, but then I don't know what to use for the package, since it's different for the release and debug versions (because of the suffix). One solution is to have a copy of the preferences.xml file in the debug resource folder with only the package changed, but this is bug-prone.
I was using option #1.1 for years but it recently broke on my phone, and I suspect the 7.1 update is to blame. I've never had cross-talk between these two installed apps before!
This has to be a pretty common pattern! Any ideas?
Please follow this steps:
After you add preferences using
addPreferencesFromResource(R.xml.preferences);
find your preference that you want to set onClick and define it by casting like
Preference pref = (Preference) findPreference("pref");
Then you can easily set its onClick using:
pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference preference) {
startActivity(new Intent(CurrentActivity.this, NextActivity.class));
return true;
}
});
Related
I have a splash activity which checks if it's the first time the user logs in or not. I am using shared preferences to save if the user already signed in or not. However, after a clean installation of the app (I uninstalled the previous version), I still get an true answer meaning that the it's not the first time of the user to sign in.
This is my if condition to check if the user already signed in:
SharedPreferences prefs = getSharedPreferences(Login.LOGIN_PREF, Context.MODE_PRIVATE);
if(prefs.contains(Login.REMEMBER_USER) &&
prefs.getBoolean(Login.REMEMBER_USER, false)) {
NetworkManager.login(SplashActivity.this, SplashActivity.this);
}
else{
Intent in = new Intent(SplashActivity.this, Login.class);
startActivity(in);
finish();
}
So the flow is: after uninstallation of the app, and then reinstalling it again, I stop at check condition and it supposed to be false, because it's a first run, however it returns true, and enters the NetworkManager part whereas it should go to the Login part.
Note: It happens only on some devices (Galaxy S6).
What can cause such odd behaviour?
If you mention android:allowBackup="true" in your Manifest file, your data will be backed up and maintained across uninstalls, which might be undesirable during development.
The default value is true.
You should need to set android:allowBackup="false" for application data not to be preserved across uninstalls.
Here is the documentation for the use of the attribute.
I found the problem. I had the following line in my manifest file under application.
<application
android:allowBackup="true"
....
</aplication>
Once I changed the value to false everything worked.
I'm sure I'm overlooking something in the Settings class documentation. What Intent can open the Settings app in the "Do not disturb" section?
I expected it to be the ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS action, but that is only for the screen which lists which apps have requested DND access.
Update
Looking at the AndroidManifest.xml for the Settings app there is an Activity Settings$ZenModeSettingsActivity already from Android 5.0.
To send the user to the "Do not disturb" screen you can use the action android.settings.ZEN_MODE_SETTINGS like this:
try {
startActivity(new Intent("android.settings.ZEN_MODE_SETTINGS"));
} catch (ActivityNotFoundException e) {
// TODO: Handle activity not found
}
Original answer
It looks like there are no screens in the Settings app (at least on Android 6+7) where you can enable/disable DND. It seems like this is only available through the settings tile (and can be disabled in the dialog when changing the volume).
I have a Samsung S6 (Android 6.0.1) which has this screen, but this is probably some custom Samsung changes. The screen is represented by the class com.android.settings.Settings$ZenModeDNDSettingsActivity which can be started by any app. This might be of help for some people out there.
AndroidManifest.xml for Settings app for Android 6+7:
https://android.googlesource.com/platform/packages/apps/Settings/+/android-6.0.1_r68/AndroidManifest.xml
https://android.googlesource.com/platform/packages/apps/Settings/+/android-7.0.0_r6/AndroidManifest.xml
You have to use the following Intent: ACTION_VOICE_CONTROL_DO_NOT_DISTURB_MODE and then pass a boolean through EXTRA_DO_NOT_DISTURB_MODE_ENABLED.
Make note that the documentation specifies the following: This intent MUST be started using startVoiceActivity.
I have a WatchFaceService (WatchFace) and every time I run my application it switches to the SimpleFace and then I have to set mine as the watchFace which ends up to be quite frustrating after many restarts.
To notice this does happen with the new Android Studio 2
I read around S.O. how to set the default activity but that does not do the same job as my WatchFaceService is not an activity but a service.
Also via the UI of Android Studio 2 it cannot be selected.
Is there a way to achieve this ? I think it might be difficult because actually it's not running an app, but setting the watch's Watchface at every run.
Any ideas?
The short answer is that this isn't possible. Your watch face is a Service, after all, so there's no way that it can be the default (launch) Activity for your app. They're completely different component classes.
But you can get close.
What you need to do is create a tiny little shell Activity that contains only the following code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = new Intent(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER)
.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT,
new ComponentName(getPackageName(),
MyWatchFaceService.class.getName()));
startActivity(intent);
finish();
}
...where MyWatchFaceService is the class name of your watch face service (surprise). You'll also need to declare it in your manifest, of course:
<activity android:name=".FaceActivity"
android:enabled="true"
android:exported="true">
</activity>
Finally, configure your Wear module in Android Studio to launch FaceActivity when you run the app. This is under the Run menu, in Edit Configurations.
Having done that, run your app from AS onto the watch, and it'll open the watch face chooser on-device, with your face selected. From there, one tap will start it.
I can't see a way to eliminate that single tap, though.
i tried coding it, i tried solving it with google and stackoverflow, nothing found :=) so hopefully someone else has a better idea, im not sure if i get everything right:
i have 2 applications: ad (main app) / adfree-pro (just license starts ad app without ads ;P)
so the problem is, i want to have a pro version (with pro icon) in the launcher, which starts the normal-ad app, which is (the normal ad-app) not in the launcher.
i tried removing the ad-app from the launcher (which due to my research should JUST remove it from the launcher)
pkgMgr.setComponentEnabledSetting(new ComponentName(PACKAGE_NAME, PACKAGE_NAME + ".Main"),
PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
which results to: the icons in the launcher are correct ;) BUT the application can't be found on the phone, launched, started, even not with a launcher pro activity shortcut. it seems to be there (shortcuts can be created) but i crashes with an activity exception when i try to launch it.
02-18 14:38:59.237: ERROR/AndroidRuntime(9941): Caused by: android.content.ActivityNotFoundException: Unable to find explicit activity class {PACKAGE_NAME/PACKAGE_NAME.Main}; have you declared this activity in your AndroidManifest.xml?
which doesnt seem to belong (the error message)
it looks like there has happened more to the application than just simply removed the entry in the launcher.
thanks a lot guys,
every workaround for this situation appreciated :)
best regards :)
You can't have app installed and hide it's launcher icon. The way I'm addressing it with my application which works similar to yours that I don't try to fight icons but instead the app can be launched using ether icon. Obviously you don't have to do in the main (free) app and the code that launches app from your pro icon will look something like the following:
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
// check if main app is installed. If yes then start it
if (appExists()) {
Log.d(TAG, "Started main app from Pro");
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("myapp://com.myapp.main"));
startActivity(intent);
finish();
} else {
// display view with link back to Market
onAppNotExists();
}
}
It's up to you to implement appExists() which is probably some sort of license check
Of course, alternatively you can develop your app's common code as library project and then distribute it in 2 flavors without duplicating the code
BUT the application can't be found on the phone, launched, started,
even not with a launcher pro activity shortcut.
Not application, but activity.
So, if your LAUNCHER activity is BaseActivity, you may create something like BaseFakeActivity (don't forget to set it as LAUNCHER in your manifest instead of your BaseActivity) and which only function is to start your BaseActivity and then finish() itself.
Now you may hide your BaseFakeActivity but you'll still be possible to interact with your BaseActivity.
P.S.: Don't forget to test your app's behaviour after doing things this way ;)
I want to open the Settings-> Sound & Display-> Phone Ringtones screen from my application. How can I do that?
Depending on your needs, there are a couple of alternatives to bring up the 'Ringtones' settings screen from your application.
If you want to bring up the actual preferences screen that is usually available through system settings -- letting your user modify the phone's universal ringtone settings through your application -- you can use the ACTION_SOUND_SETTINGS constant from the android.provider.Settings class to create a new Intent to start the sound settings activity.
startActivityForResult(new Intent(android.provider.Settings.ACTION_SOUND_SETTINGS), 0);
If you want to select a custom ringtone to use in your application you need to add a RingtonePreference in your preferences.xml definition file, like this:
<RingtonePreference
android:key="alerts_ringtone"
android:title="Select ringtone"
android:showDefault="true"
android:showSilent="true"
android:ringtoneType=""
/>
You'll be able to get the URI to the selected preference in the application's default SharedPreferences using alerts_ringtone as the key.
The latter technique uses the PreferenceActivity class to host the preference options. I won't describe that in detail here, as the Android documentation has a good writeup and some sample code.
This is an alternate solution for the problem. I am also working in the same task but the above code does not work for me. I have changed the code to
startActivityForResult(new Intent(android.provider.Settings.ACTION_SOUND_SETTINGS), 0);
and it now works.