Well, here is my impression of an upgrade feature for my Android wrapping framework (Cyborg):
It compares the versionCode of the Play-Store apk, and if the version string starts with the letter 'F', the PlayStoreModule would invoke an upgrade dialog, and would open the Play-Store, in the proper application.
I think that all the pieces are here, except for the application id, this one I got by calling on the
getPlayStoreAppDetails_Async(activity, true), I've received 10 applications details printed to the log, and one of them was mine, I took the app id and used it hard coded in the top layer application.
I use the
Android market api.
Underwent a bit of refactoring at: 24-03-2012
package com.nu.art.software.android.modules.market;
import java.io.IOException;
import java.util.List;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerCallback;
import android.accounts.AccountManagerFuture;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import com.gc.android.market.api.MarketSession;
import com.gc.android.market.api.MarketSession.Callback;
import com.gc.android.market.api.model.Market.App;
import com.gc.android.market.api.model.Market.AppsRequest;
import com.gc.android.market.api.model.Market.AppsResponse;
import com.gc.android.market.api.model.Market.ResponseContext;
import com.nu.art.software.android.core.AndroidModule;
import com.nu.art.software.android.dialogs.ForceActionDialog;
import com.nu.art.software.android.modules.configuration.ApplicationConfiguration;
import com.nu.art.software.android.utils.IntentFactory;
import com.nu.art.software.android.wrapper.R;
public final class PlayStoreModule
extends AndroidModule {
protected static final String GoogleAccountToken_Key = "A Google Account Token";
public static final String ApplicationPlaySotreId_Key = "Application Play Store ID";
private final Object TokenMonitor = new Object();
private MarketSession session;
private String sessionToken;
private Account googleAccount;
private AccountManager accountManager;
private ApplicationConfiguration configuration;
private String deviceId;
private String playStoreAppId;
private Thread applicationDetailsThread;
@Override
protected void init() {
deviceId = getGtalkAndroidId(getApplication());
configuration = getModuleOrThrowException(ApplicationConfiguration.class);
playStoreAppId = configuration.getValue(false, ApplicationPlaySotreId_Key, null);
if (playStoreAppId == null)
throw new IllegalStateException("Must add your Play-Store application id to the configuration with key: "
+ ApplicationPlaySotreId_Key);
sessionToken = configuration.getValue(true, GoogleAccountToken_Key, null);
logDebug("Loaded Google AuthToken: " + sessionToken);
accountManager = AccountManager.get(getApplication().getApplicationContext());
Thread googlePlayStoreAPI_LoadingThread = new Thread(new Runnable() {
@Override
public void run() {
synchronized (PlayStoreModule.this) {
session = new MarketSession();
session.getContext().setAndroidId(deviceId);
logDebug("Market Session - Initialized ");
}
}
}, "Google Play-Store API Initializer");
googlePlayStoreAPI_LoadingThread.start();
}
private static final Uri URI = Uri.parse("content://com.google.android.gsf.gservices");
private static final String ID_KEY = "android_id";
public static String getGtalkAndroidId(Context ctx) {
String params[] = {ID_KEY};
Cursor c = ctx.getContentResolver().query(URI, null, null, params, null);
if (!c.moveToFirst() || c.getColumnCount() < 2)
return null;
try {
return Long.toHexString(Long.parseLong(c.getString(1)));
} catch (NumberFormatException e) {
return null;
}
}
private boolean setGoogleAccountToken(final Activity activity) {
logDebug("Getting new AuthToken");
Account[] accounts = accountManager.getAccountsByType("com.google");
if (accounts.length == 0) {
sessionToken = null;
return false;
}
googleAccount = accounts[0];
AccountManagerCallback<Bundle> callBack = new AccountManagerCallback<Bundle>() {
@Override
public void run(AccountManagerFuture<Bundle> accountManagerFuture) {
Bundle bundle;
try {
bundle = accountManagerFuture.getResult();
sessionToken = bundle.getString(AccountManager.KEY_AUTHTOKEN);
logDebug("Google New AuthToken: " + sessionToken);
configuration.putValue(true, GoogleAccountToken_Key, sessionToken);
synchronized (TokenMonitor) {
TokenMonitor.notify();
}
} catch (OperationCanceledException e) {
logError(e);
} catch (AuthenticatorException e) {
accountManager.invalidateAuthToken("com.google", sessionToken);
} catch (IOException e) {
logError(e);
}
}
};
accountManager.getAuthToken(googleAccount, "android", null, activity, callBack, null);
return true;
}
public final void checkIfForceUpdateIsInOrder(final Activity activity) {
checkIfForceUpdateIsInOrder(activity, false);
}
public final void checkIfForceUpdateIsInOrder(final Activity activity, final boolean list) {
if (applicationDetailsThread != null)
return;
applicationDetailsThread = new Thread(new Runnable() {
@Override
public void run() {
process();
applicationDetailsThread = null;
}
private void process() {
boolean waitForToken = false;
// if (sessionToken == null)
waitForToken = setGoogleAccountToken(activity);
if (waitForToken)
synchronized (TokenMonitor) {
try {
logDebug("Waiting for google account token");
TokenMonitor.wait(20000);
} catch (InterruptedException e) {
logError("Erroe while waiting for Account token", e);
return;
}
}
// Launch race condition workaround
if (sessionToken == null)
return;
logDebug("Get Application Details");
synchronized (PlayStoreModule.this) {
getApplicationDetails(activity, list);
}
}
}, "Play-Store Application Details fetcher workaround Thread");
applicationDetailsThread.start();
}
private final void getApplicationDetails(final Activity activity, boolean list) {
session.setAuthSubToken(sessionToken);
com.gc.android.market.api.model.Market.AppsRequest.Builder builder = AppsRequest.newBuilder();
builder.setStartIndex(0);
if (list) {
builder.setQuery(getApplication().getName());
builder.setEntriesCount(10);
} else {
builder.setAppId(playStoreAppId);
builder.setEntriesCount(1);
}
// builder.setWithExtendedInfo(true);
logDebug("AppsRequest.Builder: " + builder);
AppsRequest appsRequest = builder.build();
session.append(appsRequest, new Callback<AppsResponse>() {
@Override
public void onResult(ResponseContext context, AppsResponse response) {
List<App> apps = response.getAppList();
logDebug("ResponseContext: " + context);
logDebug("AppsResponse: " + response);
App app;
if (apps.size() != 1)
return;
app = apps.get(0);
int latestVersionCodeFound = app.getVersionCode();
String latestVersionFound = app.getVersion();
if (latestVersionCodeFound <= getApplication().getVersionCode()) {
logDebug("No upgrade in market.");
return;
}
if (!latestVersionFound.startsWith("F")) {
logDebug("Newer (NOT MANDATORY) version is now available in Google play store (v:" + latestVersionFound + ", vc:" + latestVersionCodeFound + ").");
return;
}
logDebug("Newer (MANDATORY) version is now available in Google play store (v:" + latestVersionFound + ", vc:" + latestVersionCodeFound + ").");
final ForceActionDialog dialog = getUpgradeDialog(activity);
String body = dialog.getBody();
body = body.replace("${version}", latestVersionFound);
dialog.setBody(body);
dialog.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
dialog.dismiss();
Intent intent = IntentFactory.openMarketApplicationDetails(activity.getApplicationContext().getPackageName());
activity.startActivity(intent);
}
}, "Upgrade APK Installer");
thread.start();
}
});
dialog.showDialog();
}
});
try {
session.flush();
} catch (Exception e) {
logError(e);
sessionToken = null;
toast("Error checking for Upgrade", LongToast);
}
}
protected ForceActionDialog getUpgradeDialog(final Activity activity) {
final ForceActionDialog dialog = new ForceActionDialog(activity, R.string.UpgradeRequired, R.string.NeedToUpgradeApplicationMessage,
R.string.Upgrade);
dialog.setCancelableFlag(false);
return dialog;
}
}
|
Java2html
|