/* * Copyright (C) 2010 The Android Open Source Project * Modifications copyright (C) 2012-2014 Saikoa / Itsana BVBA * * 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.example.android.market.licensing; import com.google.android.vending.licensing.AESObfuscator; import com.google.android.vending.licensing.LicenseChecker; import com.google.android.vending.licensing.LicenseCheckerCallback; import com.google.android.vending.licensing.Policy; import com.google.android.vending.licensing.ServerManagedPolicy; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.provider.Settings.Secure; import android.view.View; import android.view.Window; import android.widget.Button; import android.widget.TextView; /** * Welcome to the world of Android Market licensing. We're so glad to have you * onboard! * <p> * The first thing you need to do is get your hands on your public key. * Update the BASE64_PUBLIC_KEY constant below with your encoded public key, * which you can find on the * <a href="http://market.android.com/publish/editProfile">Edit Profile</a> * page of the Market publisher site. * <p> * Log in with the same account on your Cupcake (1.5) or higher phone or * your FroYo (2.2) emulator with the Google add-ons installed. Change the * test response on the Edit Profile page, press Save, and see how this * application responds when you check your license. * <p> * After you get this sample running, peruse the * <a href="http://developer.android.com/guide/publishing/licensing.html"> * licensing documentation.</a> */ public class MainActivity extends Activity { // Some random RSA key, not actually suitable for the Google Play store. // Replace this with the public key from your Google Play profile. // We'll let DexGuard encrypt it. private static final String BASE64_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+T3PmaVTzJZYt75vi4+EQKDp6wgtFTzAwTRENX0Tw0EIT+55zNfMaI4LfgSjF6jCl7zxl7hH7u8NG9/MmrdNMsR5w9Tob9qsH0kPoK0TXh7wFY00umEKEj+v+7gxsLqzyAS1OPka7KZXTFU8QWcbcTf2FOmk2v/tn/p212gwlcQIDAQAB"; // Generate your own 20 random bytes, and put them here. private static final byte[] SALT = new byte[] { -46, 65, 30, -128, -103, -57, 74, -64, 51, 88, -95, -45, 77, -117, -36, -113, -11, 32, -64, 89 }; private TextView mStatusText; private Button mCheckLicenseButton; private LicenseCheckerCallback mLicenseCheckerCallback; private LicenseChecker mChecker; // A handler on the UI thread. private Handler mHandler; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); setContentView(R.layout.main); mStatusText = (TextView) findViewById(R.id.status_text); mCheckLicenseButton = (Button) findViewById(R.id.check_license_button); mCheckLicenseButton.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { doCheck(); } }); mHandler = new Handler(); // Try to use more data here. ANDROID_ID is a single point of attack. // => We'll let DexGuard encrypt the string. String deviceId = Secure.getString(getContentResolver(), Secure.ANDROID_ID); // Library calls this when it's done. mLicenseCheckerCallback = new MyLicenseCheckerCallback(); // Construct the LicenseChecker with a policy. mChecker = new LicenseChecker( this, new ServerManagedPolicy(this, new AESObfuscator(SALT, getPackageName(), deviceId)), BASE64_PUBLIC_KEY); doCheck(); } protected Dialog onCreateDialog(int id) { final boolean bRetry = id == 1; return new AlertDialog.Builder(this) .setTitle(R.string.unlicensed_dialog_title) .setMessage(bRetry ? R.string.unlicensed_dialog_retry_body : R.string.unlicensed_dialog_body) .setPositiveButton(bRetry ? R.string.retry_button : R.string.buy_button, new DialogInterface.OnClickListener() { boolean mRetry = bRetry; public void onClick(DialogInterface dialog, int which) { if ( mRetry ) { doCheck(); } else { Intent marketIntent = new Intent(Intent.ACTION_VIEW, Uri.parse( "http://market.android.com/details?id=" + getPackageName())); startActivity(marketIntent); } } }) .setNegativeButton(R.string.quit_button, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { finish(); } }).create(); } private void doCheck() { mCheckLicenseButton.setEnabled(false); setProgressBarIndeterminateVisibility(true); mStatusText.setText(R.string.checking_license); mChecker.checkAccess(mLicenseCheckerCallback); } private void displayResult(final String result) { mHandler.post(new Runnable() { public void run() { mStatusText.setText(result); setProgressBarIndeterminateVisibility(false); mCheckLicenseButton.setEnabled(true); } }); } private void displayDialog(final boolean showRetry) { mHandler.post(new Runnable() { public void run() { setProgressBarIndeterminateVisibility(false); showDialog(showRetry ? 1 : 0); mCheckLicenseButton.setEnabled(true); } }); } private class MyLicenseCheckerCallback implements LicenseCheckerCallback { public void allow(int policyReason) { if (isFinishing()) { // Don't update UI if Activity is finishing. return; } // Should allow user access. displayResult(getString(R.string.allow)); } public void dontAllow(int policyReason) { if (isFinishing()) { // Don't update UI if Activity is finishing. return; } displayResult(getString(R.string.dont_allow)); // Should not allow access. In most cases, the app should assume // the user has access unless it encounters this. If it does, // the app should inform the user of their unlicensed ways // and then either shut down the app or limit the user to a // restricted set of features. // In this example, we show a dialog that takes the user to Market. // If the reason for the lack of license is that the service is // unavailable or there is another problem, we display a // retry button on the dialog and a different message. displayDialog(policyReason == Policy.RETRY); } public void applicationError(int errorCode) { if (isFinishing()) { // Don't update UI if Activity is finishing. return; } // This is a polite way of saying the developer made a mistake // while setting up or calling the license checker library. // Please examine the error code and fix the error. String result = String.format(getString( BASE64_PUBLIC_KEY.hashCode() == 970210445 ? R.string.replace_public_key : R.string.application_error), errorCode); displayResult(result); } } @Override protected void onDestroy() { super.onDestroy(); mChecker.onDestroy(); } }