/*
* Copyright (C) 2009 Tony Gentilcore
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.scoreninja.adapter;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager.NameNotFoundException;
/**
* Manages communication with the ScoreNinja service.
*
* Example usage:
* public class MyGame extends Activity {
* private ScoreNinjaAdapter scoreNinjaAdapter;
*
* @Override
* protected void onCreate(Bundle savedInstanceState) {
* ...
* scoreNinjaAdapter = new ScoreNinjaAdapter(myContext, "myAppId", "myPrivateKey");
* }
*
* @Override
* protected void onActivityResult(int requestCode, int resultCode, Intent data) {
* super.onActivityResult(requestCode, resultCode, data);
* scoreNinjaAdapter.onActivityResult(requestCode, resultCode, data);
* }
*
* void onGameOver() {
* scoreNinjaAdapter.show(playersNewScore);
* }
* }
*
* @author tonygentilcore@gmail.com (Tony Gentilcore)
*/
public final class ScoreNinjaAdapter {
// Intent and Bundle keys.
private static final String KEY_APP_ID = "appid";
private static final String KEY_NEW_SCORE = "newscore";
private static final String KEY_SIGNATURE = "signature";
private static final String KEY_COMMENTS = "comments";
private static final String KEY_LOCATION = "location";
private static final String KEY_NAME = "name";
private static final String KEY_TITLE = "title";
private static final String KEY_SUB_BOARD = "subboard";
private static final String KEY_ORIENTATION = "orientation";
private static final int REQUEST_CODE = 987656789; // Can be anything that is unlikely to collide.
final static String PREFS_NAME = "ScoreNinjaPrefs";
final static String NEVER_ASK_PREF = "neverask";
public final static String PACKAGE = "com.scoreninja";
private final static String ACTIVITY_CLASS = PACKAGE + ".ScoreNinja";
private final static String SERVICE_CLASS = PACKAGE + ".ScoreNinjaService";
private final Activity parent;
private final String appId;
private final RequestSigner signer;
private int orientation = -1;
/**
* Creates a new ScoreNinjaAdapter which is capable of invoking the ScoreNinja
* activity.
*
* @param context The parent Activity that is creating this adapter. It is
* used to start the intents that invoke the ScoreNinja.
* @param appId The application ID of the calling application. To obtain an
* application ID, visit http://scoreninja.appsot.com/ .
* @param privateKey The private key associated with the given appId. Private
* keys are issued when new application IDs are created.
*/
public ScoreNinjaAdapter(Context context, String appId, String privateKey) {
this.parent = (Activity) context;
this.appId = appId;
this.signer = new RequestSigner(privateKey);
}
/**
* By default the orientation of the scoreboard is the same as the parent
* activity. However, if your game does something creative with orientation
* you may override that default orientation here.
*
* @param orientation Any of the SCREEN_ORIENTATION constants in
* android.content.pm.ActivityInfo. Commonly SCREEN_ORIENTATION_LANDSCAPE or
* SCREEN_ORIENTATION_PORTRAIT.
*/
public void setRequestedOrientation(int orientation) {
this.orientation = orientation;
}
/**
* Display the top 10 list without a new score.
* If the com.scoreninja package is not installed, the user will be prompted
* to install it.
*/
public void show() {
show(0);
}
/**
* Display the top 10 list with the given new score. If the newScore is in the
* top 10, the user will be prompted to enter their name and comments.
* Otherwise the user's ranking will be displayed at the bottom of the top 10.
* If the com.scoreninja package is not installed, the user will be prompted
* to install it.
*
* @param newScore The most recent score achieved by the user.
*/
public void show(int newScore) {
show(newScore, null, null);
}
/**
* Display the top 10 list with the given new score. If the newScore is in the
* top 10, the user will be prompted to enter their name and comments.
* Otherwise the user's ranking will be displayed at the bottom of the top 10.
* If the com.scoreninja package is not installed, the user will be prompted
* to install it.
*
* @param newScore The most recent score achieved by the user.
* @param titleText If non-null, the text to display in the title bar of the
* window.
* @param subBoard If non-null, an arbitrary name of a sub-board to display
* and apply this newScore to if it qualifies. This can be used to,
* for example, create a separate board for "easy", "medium", "hard".
*/
public void show(int newScore, String titleText, String subBoard) {
if (isInstalled(parent)) {
Intent i = new Intent();
i.setAction(Intent.ACTION_VIEW);
i.addCategory(Intent.CATEGORY_DEFAULT);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
i.setClassName(PACKAGE, ACTIVITY_CLASS);
i.putExtra(KEY_APP_ID, appId);
if (titleText != null) i.putExtra(KEY_TITLE, titleText);
i.putExtra(KEY_NEW_SCORE, newScore);
if (subBoard != null) i.putExtra(KEY_SUB_BOARD, subBoard);
if (orientation != -1) i.putExtra(KEY_ORIENTATION, orientation);
i.putExtra(KEY_SIGNATURE, signer.getSignature(appId + newScore + (subBoard != null ? subBoard : "")));
try {
parent.startActivityIfNeeded(i, REQUEST_CODE);
} catch (ActivityNotFoundException e) {
// This should not happen, but would probably mean it is not installed,
// fail silently.
}
} else if (!neverAskAgain(parent)) {
new ScoreNinjaInstallAlert(parent).show();
}
}
/**
* Must be invoked from the parent Activity's onActivityResult() method.
* Failure to do so will prevent any new scores from being submitted.
*
* @param requestCode
* @param resultCode
* @param intent
*/
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (resultCode == Activity.RESULT_OK &&
requestCode == REQUEST_CODE &&
intent != null) {
int newScore = intent.getIntExtra(KEY_NEW_SCORE, 0);
String signature = intent.getStringExtra(KEY_SIGNATURE);
String subBoard = intent.getStringExtra(KEY_SUB_BOARD);
String scoreSignature = signer.getSignature(appId + newScore + (subBoard != null ? subBoard : ""));
if (newScore < 1 || !scoreSignature.equals(signature)) {
return;
}
Intent newIntent = new Intent();
newIntent.setClassName(PACKAGE, SERVICE_CLASS);
newIntent.setAction(Intent.ACTION_SEND);
newIntent.putExtra(KEY_APP_ID, appId);
newIntent.putExtra(KEY_NEW_SCORE, newScore);
if (subBoard != null) newIntent.putExtra(KEY_SUB_BOARD, subBoard);
if (intent.hasExtra(KEY_NAME) && intent.hasExtra(KEY_COMMENTS)) {
String name = intent.getStringExtra(KEY_NAME);
String comments = intent.getStringExtra(KEY_COMMENTS);
String location = intent.getStringExtra(KEY_LOCATION);
newIntent.putExtra(KEY_NAME, name);
newIntent.putExtra(KEY_COMMENTS, comments);
newIntent.putExtra(KEY_SIGNATURE, signer.getSignature(appId + newScore + (subBoard != null ? subBoard : "")
+ name + comments + (location != null ? location : "")));
} else {
newIntent.putExtra(KEY_SIGNATURE, scoreSignature);
}
parent.startService(newIntent);
}
}
/**
* Checks if we are allowed to ask to install again
*
* @return A boolean that indicates whether we should never ask again
*/
public static boolean neverAskAgain(Context ctx) {
SharedPreferences settings = ctx.getSharedPreferences(PREFS_NAME, 0);
return settings.getBoolean(NEVER_ASK_PREF, false);
}
/**
* Checks if the service is installed or not
*
* @return A boolean that indicates whether the service is installed
*/
public static boolean isInstalled(Context ctx) {
try {
@SuppressWarnings("unused")
Context unusedContext = ctx.createPackageContext(
ScoreNinjaAdapter.PACKAGE, 0);
} catch (NameNotFoundException e) {
return false;
}
return true;
}
}
|