NEXT_ALARM_FORMATTED is deprecated - android

Since API 21 / Android 5.0
The field Settings.System.NEXT_ALARM_FORMATTED is deprecated
What is the alternative for doing this? I saw http://developer.android.com/reference/android/app/AlarmManager.html#getNextAlarmClock()
But I really don't know how to implement it.

You should upgrade android to api level 21 and your device also should be compatible with that,
you can remove try..catch block also but it is better if in your manifest.xml android:minSdkVersion is less than 21.
try {
AlarmManager am = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
am.getNextAlarmClock();
Log.d("Nextalarm", am.getNextAlarmClock().toString());
} catch (NoSuchMethodError e) {
e.printStackTrace();
}

getNextAlarmClock() is a public method in AlarmManager class which was introduced in API level 21. You need to install API level 21 in order to use this method. Also, make necessary changes in Android Project Build Target.

I needed some code to simply test if any alarms exist, so I can update a graphic on a full screen app. Thank you to everyone who contributed. Based on all that, here is what I ended up implementing:
private void testAlarms() {
String nextAlarm = null;
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
AlarmManager am = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
am.getNextAlarmClock();
try {
nextAlarm = am.getNextAlarmClock().toString();
} catch (Exception e) {
e.printStackTrace();
}
} else {
nextAlarm = Settings.System.getString(getContentResolver(),Settings.System.NEXT_ALARM_FORMATTED);
}
if(TextUtils.isEmpty(nextAlarm)) {
hideAlarm();
} else {
showAlarm();
}
}

Related

Android can't find method removeAccount

I have implemented accounts for my app following this tutorial http://blog.udinic.com/2013/04/24/write-your-own-android-authenticator/
Every aspect of the implementation works great except when I try to remove the account with the following code:
public void logout(View view) {
// remove account and restart app
stopService(new Intent(this, ServerSync.class));
Account account = AccountManager.get(this).getAccountsByType(Constants.ACCOUNT_TYPE)[0];
final AccountManagerFuture<Bundle> future = AccountManager.get(this).removeAccount(account, this, new AccountManagerCallback<Bundle>() {
#Override
public void run(AccountManagerFuture<Bundle> future) {
try {
future.getResult();
} catch (Exception e) {
e.printStackTrace();
} finally {
Intent intent = getBaseContext().getPackageManager()
.getLaunchIntentForPackage(getBaseContext().getPackageName());
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
finish();
startActivity(intent);
}
}
}, null);
}
When called this produces
NoSuchMethodError: android.accounts.AccountManager.removeAccount
and the app crashes.
I have followed the Android documentation
http://developer.android.com/reference/android/accounts/AccountManager.html
and my app has the correct permissions etc. I even tried overriding getAccountRemovalAllowed in my AccountAuthenticator, forcing it to return true.
Is there some other information missing from the Android documentation?
the version of removeAccount you are using was introduced with the api leve 22 and you are probably using it on a version of Android older than it. You should check the current version at runtime and use the deprecated version of removeAccount for devices with version of Android older than 22
removeAccount (Account account, AccountManagerCallback callback, Handler handler)
if (Build.VERSION.SDK_INT < 22) {
AccountManager.get(this).removeAccount(account, new AccountManagerCallback<Bundle>(){....}, null)
} else {
// the version you are already using
}

Support deprecated and new API

Is there any way I can support both deprecated and new API in the same method call for Android? I'm using the camera API which seems to be deprecated for the Lollipop version, so I tried to handle it like this:
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.LOLLIPOP)
{
//Before Lollipop, use the Camera API since it still supported.
}
else
{
//Use the CameraManager
try
{
for (int i= 0; i < _camera.getCameraIdList().length; i++)
{
System.out.println("Camera= " + _camera.getCameraIdList()[i]);
}
}
catch (CameraAccessException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
But this does however just give me the error Call requires API level 21 (current min is 15): android.hardware.camera2.CameraManager#getCameraIdList
I tried SupressLint and TargetApi but that only made the device running an earlier (before Lollipop) Android version crash when creating an class instance of this type.
Thanks for any help!
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
//handler lollipop and higher
} else {
//earlier api calls
}
Simply having code in a class does not crash any Android 2.0+ device - code actually needs to run for it to crash. Check to make sure all of your Lollipop specific code is wrapped in version checks.

Why does removeOnGlobalLayoutListener throw a NoSuchMethodError?

I have some code that compiles successfully using ViewTreeObserver#removeOnGlobalLayoutListener(...) and when it runs, this method throws NoSuchMethodError. Why?
There are two methods in ViewTreeObserver with almost the same name.
removeOnGlobalLayoutListener(ViewTreeObserver.OnGlobalLayoutListener victim)
(on then global) is a method that was added in API 16. It replaces
removeGlobalOnLayoutListener(ViewTreeObserver.OnGlobalLayoutListener victim)
(global then on) which has existed since API 1, but which is now deprecated.
Both methods can appear present at compile-time (if you're building against Jellybean or higher) but the newer one will fail on pre-Jellybean devices.
This code thwarts the error:
try {
thing.removeOnGlobalLayoutListener(victim);
} catch (NoSuchMethodError x) {
thing.removeGlobalOnLayoutListener(victim);
}
So does this code:
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
thing.removeGlobalOnLayoutListener(victim);
} else {
thing.removeOnGlobalLayoutListener(victim);
}
I assume you are talking about removeOnGlobalLayoutListener from ViewTreeObserver class. This method was added in API level 16. My best guess is that you try to use it on a device running an old version of Android that's why it can't be found.
I have working code
public static void removeOnGlobalLayoutListener(View v, ViewTreeObserver.OnGlobalLayoutListener listener){
if (Build.VERSION.SDK_INT < 16) {
v.getViewTreeObserver().removeGlobalOnLayoutListener(listener);
} else {
v.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
}
}

can an android application check the version of the phone

I would like to write an application that uses live wallpapers for insatnce. this feature is supported only in version 7 and up. Is it posiible, that the application checks the version of the android phone and depending on that runs different code (e.g. uses live wallpaper or static background.)
Do you have a code example for that? Does that require special permissions?
Assuming you're requiring Android 1.6 or newer:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR_MR1) {
...
}
Yes there is. Look at the Build class in Android. You can use it like so Build.VERSION.SDK_INT
public static final int ECLAIR_MR1 =7;
public static final int FROYO =8;
if(Build.VERSION.SDK_INT==FROYO){
Toast.makeText(getApplicationContext(), "Iam a FROYO-Phone", 1).show();
}else if(Build.VERSION.SDK_INT==ECLAIR_MR1){
Toast.makeText(getApplicationContext(), "Iam an ECLAIR-Phone", 1).show();
}
SDK_INT is not available on very early builds. So if your manifest has for instance:
android:minSdkVersion="1"
you can use something like this:
#TargetApi(Build.VERSION_CODES.DONUT)
static boolean getPreHoneyComb() {
try {
Build.VERSION.class.getField("SDK_INT");
}
catch (NoSuchFieldException e) {
return true;
}
return Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB;
}

Backwards-compatible BackupAgent

I am looking into using the new Backup API that available since Android 2.2, but need to maintain backwards compatibility (to 1.5 to be exact).
The docs state:
The backup service and the APIs you must use are available only on devices running API Level 8 (Android 2.2) or greater, so you should also set your android:minSdkVersion attribute to "8". However, if you implement proper backward compatibility in your application, you can support this feature for devices running API Level 8 or greater, while remaining compatible with older devices.
I indeed build against the level 8 targetSdkVersion with level 3 minSdkVersion and try to use a wrapper class (with reflection) to overcome the problem that the application will not run if you implement a class that extends an nonexisting class.
Here is the problem: since we don't make actual calls to the BackupHelper class ourselves, we can't check upfront if the class indeed exists. (As is explained in the Android Backwards Compatibility documentation with a checkAvailable() method.) The class will therefore be instantiated and cast to a BackupAgent. But since we use reflection, it doesn't actually override BackupAgent and an exception occurs at runtime when the backup is requested:
java.lang.RuntimeException: Unable to create BackupAgent org.transdroid.service.BackupAgent: java.lang.ClassCastException: org.transdroid.service.BackupAgent
Here is my approach to a backwards compatible BackupAgent: http://code.google.com/p/transdroid/source/browse/#svn/trunk/src/org/transdroid/service where the BackupAgent.java is the 'regular' BackupAgentHelper-extending class and BackupAgentHelperWrapper is the reflection-based wrapper class.
Anyone successfull in implementing a BackupAgent with backwards compatibility?
As an alternative, you can just use pure reflection to talk to the BackupManager:
public void scheduleBackup() {
Log.d(TAG, "Scheduling backup");
try {
Class managerClass = Class.forName("android.app.backup.BackupManager");
Constructor managerConstructor = managerClass.getConstructor(Context.class);
Object manager = managerConstructor.newInstance(context);
Method m = managerClass.getMethod("dataChanged");
m.invoke(manager);
Log.d(TAG, "Backup requested");
} catch(ClassNotFoundException e) {
Log.d(TAG, "No backup manager found");
} catch(Throwable t) {
Log.d(TAG, "Scheduling backup failed " + t);
t.printStackTrace();
}
}
Point the android:backupAgent straight at a v2.2 class; it will never be loaded on a pre-v2.2 VM, so there won't be any linkage problems.
I don't see why you run into this problem.
I have the same issue: I want to support backup with a app that supports also 1.5 (API 3).
There is no problem in creating my BackupAgentHelper class, since that class is never called from my own code, but from the BackupManager i.e. the system itself. Therefore I don't need to wrap it, and I don't see why you should be doing that:
public class MyBackupAgentHelper extends BackupAgentHelper {
#override onCreate()
{
\\do something usefull
}
However, you do want to get a backup running, to do that you need to call on BackupManager.dataChanged() whenever your data changes and you want to inform the system to backup it (using your BackupAgent or BackupAgentHelper).
You do need to wrap that class, since you call it from you application code.
public class WrapBackupManager {
private BackupManager wrappedInstance;
static
{
try
{
Class.forName("android.app.backup.BackupManager");
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
public static void checkAvailable() {}
public void dataChanged()
{
wrappedInstance.dataChanged();
}
public WrapBackupManager(Context context)
{
wrappedInstance = new BackupManager(context);
}
}
You then call it from your code when you change a preference or save some data.
Some code from my app:
private static Boolean backupManagerAvailable = null;
private static void postCommitAction() {
if (backupManagerAvailable == null) {
try {
WrapBackupManager.checkAvailable();
backupManagerAvailable = true;
} catch (Throwable t) {
backupManagerAvailable = false;
}
}
if (backupManagerAvailable == true) {
Log.d("Fretter", "Backup Manager available, using it now.");
WrapBackupManager wrapBackupManager = new WrapBackupManager(
FretterApplication.getApplication());
wrapBackupManager.dataChanged();
} else {
Log.d("Fretter", "Backup Manager not available, not using it now.");
}
So, hopefully this works for you!
(If you call adb shell bmgr run every time you want to emulate the actual system initiated backupprocess it should properly backup and restore when you reinstall the app.)
You need to set the minSDK version to the following:
<uses-sdk android:minSdkVersion="3" android:targetSdkVersion="8"/>
and setting the build target to sdk 8 (project properties in eclipse '.default.properties'):
# Project target.
target=android-8
Now to call new stuff added in SDK 8 you have to use reflection: http://developer.android.com/resources/articles/backward-compatibility.html
I ran into the same problem and here's what I did to work it out.
You don't extend BackupAgent with the wrapper, you extend it with the wrapped class. So you make your real backup class:
public class MyBackup extends BackupAgent {
#Override
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState) throws IOException {
// TODO Auto-generated method stub
}
#Override
public void onRestore(BackupDataInput data, int appVersionCode,
ParcelFileDescriptor newState) throws IOException {
// TODO Auto-generated method stub
}
Okay, and then you make a wrapper like the android developer backwards compatibility article said to do. Note that this class does not extend BackupAgent:
public class WrapMyBackup {
private MyBackup wb;
static {
try {
Class.forName("MyBackup");
}
catch (Exception ex) {
throw new RuntimeException(ex);
}
}
/** call this wrapped in a try/catch to see if we can instantiate **/
public static void checkAvailable() {}
public WrapMyBackup() {
wb = new MyBackup();
}
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState) throws IOException {
wb.onBackup(oldState, data, newState);
}
public void onRestore(BackupDataInput data, int appVersionCode,
ParcelFileDescriptor newState) throws IOException {
wb.onRestore(data, appVersionCode, newState);
}
public void onCreate() {
wb.onCreate();
}
public void onDestroy() {
wb.onDestroy();
}
}
Finally, in your manifest, you declare the wrapper as your backup agent:
<application
android:label="#string/app_name"
android:icon="#drawable/ic_launch_scale"
android:backupAgent="WrapMyBackup"
>
Since your wrapper has the proper methods defined you won't run into a problem when the backup manager casts it to a BackupAgent. Since lower API levels won't have a BackupManager the code will never get called, so you won't run into any runtime exceptions there either.
How about
if (android.os.Build.VERSION.SDK_INT >= 8)
{
BackupManager bm = new BackupManager(this);
bm.dataChanged();
}
Insted of just calling BackupManager.dataChanged, check if the class exists first.
try {
Class.forName("android.app.backup.BackupManager");
BackupManager.dataChanged(context.getPackageName());
} catch (ClassNotFoundException e) {
}

Categories

Resources