/**
* Copyright (C) 2013 Johannes Schnatterer
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This file is part of nusic.
*
* nusic is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* nusic is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with nusic. If not, see <http://www.gnu.org/licenses/>.
*/
package info.schnatterer.nusic.android.application;
import info.schnatterer.nusic.android.util.ResourceUtil;
import java.io.InputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import android.annotation.TargetApi;
import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
/**
* Extended version of {@link Application} that contains a version number
* mechanism similar to the one of
* {@link android.database.sqlite.SQLiteOpenHelper}: It calls
* {@link #onUpgrade(int, int)} on the derived concrete application class.<br/>
* <br/>
* <b>Important:</b> In the concrete class, call <code>super.onCreate()</code>
* at the end of the concrete class' {@link #onCreate()} method.
*
* @author schnatterer
*
*/
public abstract class AbstractApplication extends Application {
private static final Logger LOG = LoggerFactory
.getLogger(AbstractApplication.class);
/** Name of the shared prefernces file used to store the app versions. */
static final String SHARED_PREFERENCES_NAME = "AbstractApplicationPreferences";
static final String KEY_LAST_APP_VERSION = "last_app_version";
/** Last app version on first start ever of the app. */
static final int DEFAULT_LAST_APP_VERSION = -1;
private static boolean isInitialized = false;
private static int lastVersionCode;
private static int currentVersionCode;
private static String currentVersionName;
private static AppStart appStart = null;
@Override
public void onCreate() {
super.onCreate();
initGlobals();
handleAppVersion();
}
/**
* Initializes "global" variables that are statically provided by the class. <br/>
* <br/>
* Note that this is also called by {@link #onCreate()}, so use this only if
* you might need to initialize the global context before calling
* {@link #onCreate()}.
*/
protected void initGlobals() {
if (!isInitialized) {
currentVersionName = ResourceUtil
.createVersionName(getApplicationContext());
isInitialized = true;
}
}
/**
* Finds out if app was started for the first time (after an upgrade). If so
* calls {@link #onUpgrade(int, int)}.
*
* @return
*
*/
void handleAppVersion() {
PackageInfo pInfo;
try {
pInfo = getApplicationContext().getPackageManager().getPackageInfo(
getApplicationContext().getPackageName(), 0);
SharedPreferences sharedPreferences = getApplicationContext()
.getSharedPreferences(SHARED_PREFERENCES_NAME,
Context.MODE_PRIVATE);
lastVersionCode = sharedPreferences.getInt(KEY_LAST_APP_VERSION,
DEFAULT_LAST_APP_VERSION);
// String versionName = pInfo.versionName;
currentVersionCode = pInfo.versionCode;
// Update version in preferences
LOG.debug("handleAppVersion(): currentVersionCode="
+ currentVersionCode + "; lastVersionCode="
+ lastVersionCode);
if (currentVersionCode != lastVersionCode) {
sharedPreferences.edit()
.putInt(KEY_LAST_APP_VERSION, currentVersionCode)
.commit();
if (lastVersionCode == DEFAULT_LAST_APP_VERSION) {
appStart = AppStart.FIRST;
onFirstCreate();
return;
} else {
onUpgrade(lastVersionCode, currentVersionCode);
appStart = AppStart.UPGRADE;
return;
}
}
} catch (NameNotFoundException e) {
LOG.warn("Unable to determine current app version from pacakge manager. Defenisvely assuming normal app start.");
}
appStart = AppStart.NORMAL;
return;
}
/**
* Called when app is started for the first time after a new installation.
* This is where an initial welcome screen could be shown.
*
* @return
*/
protected abstract void onFirstCreate();
/**
* Called when app was first started after an upgrade. The implementation
* should use this method to clean up preferences no longer needed show
* change log or do anything else it needs to upgrade to the new version.
*
* @param oldVersion
* the version the app was last started with
* @param newVersion
* the current version of the app
*/
protected abstract void onUpgrade(int oldVersion, int newVersion);
/**
* @return the human readable version name.
*/
public static String getCurrentVersionName() {
return currentVersionName;
}
/**
* Finds out if app was started for the first time (ever or in the current
* version).<br/>
* <b>Note:</b> Be careful when using this for creating welcome screens,
* e.g. in {@link android.app.Activity}.onCreate(), as this information is
* gathered on the first start and kept in memory statically. The app might
* be redrawn multiple times during the lifetime of this information. That
* is onCreate() will be called multiple times but the welcome screen is
* supposed to be shown only once. So addition logic is necessary within the
* activity to distinguish if this is the first time the activity is
* created.
*
* @return the type of app start
*/
public static AppStart getAppStart() {
return appStart;
}
/**
* Distinguishes different kinds of app starts: <li>
* <ul>
* First start ever ({@link #FIRST})
* </ul>
* <ul>
* First start in this version ({@link #UPGRADE})
* </ul>
* <ul>
* Normal app start ({@link #NORMAL})
* </ul>
*
* @author schnatterer
*
*/
public enum AppStart {
FIRST, UPGRADE, NORMAL;
}
public static int getLastVersionCode() {
return lastVersionCode;
}
public static int getCurrentVersionCode() {
return currentVersionCode;
}
protected static void setAppStart(AppStart appStart) {
AbstractApplication.appStart = appStart;
}
protected static void setLastVersionCode(int lastVersionCode) {
AbstractApplication.lastVersionCode = lastVersionCode;
}
public Bitmap createScaledBitmap(InputStream inputStream) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
return createScaledBitmapLegacy(inputStream);
} else {
return createScaledBitmapModern(inputStream);
}
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private Bitmap createScaledBitmapModern(InputStream inputStream) {
Bitmap artwork = null;
artwork = Bitmap.createScaledBitmap(
BitmapFactory.decodeStream(inputStream),
(int) this.getResources().getDimension(
android.R.dimen.notification_large_icon_width),
(int) this.getResources().getDimension(
android.R.dimen.notification_large_icon_height), false);
return artwork;
}
private Bitmap createScaledBitmapLegacy(InputStream inputStream) {
/*
* As we don't know the size of the notification icon bellow API lvl 11,
* theses devices will just use the standard icon.
*/
return null;
}
}