Java tutorial
/* * Copyright (C) 2015 Phonemetra * * 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.phonemetra.account.util; import android.content.ComponentName; import android.os.Bundle; import android.os.UserManager; import com.phonemetra.account.Account; import com.phonemetra.account.R; import com.phonemetra.account.auth.AuthClient; import com.phonemetra.account.auth.UpdateRequiredActivity; import com.phonemetra.account.ui.WebViewDialogFragment; import android.accounts.Account; import android.accounts.AccountManager; import android.app.Activity; import android.app.AlarmManager; import android.app.Fragment; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.graphics.drawable.BitmapDrawable; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.wifi.WifiManager; import android.os.SystemClock; import android.os.SystemProperties; import android.provider.Settings; import android.telephony.TelephonyManager; import android.util.Base64; import android.util.Log; import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.binary.Hex; import org.spongycastle.math.ec.ECFieldElement; import java.math.BigInteger; import java.net.NetworkInterface; import java.net.SocketException; import java.security.MessageDigest; import java.sql.Timestamp; import java.util.Collections; import java.util.List; import java.util.Random; import java.util.regex.Pattern; import org.apache.commons.codec.binary.Hex; public class AccountUtils { private static final String TAG = AccountUtils.class.getSimpleName(); private static final Random sRandom = new Random(); private static final Long INTERVAL_WEEK = 604800000L; public static final Pattern EMAIL_ADDRESS = Pattern.compile("[a-zA-Z0-9\\+\\.\\_\\%\\-\\+]{1,256}" + "\\@" + "[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}" + "(" + "\\." + "[A-Za-z]{2,6}" + ")+"); private static final String KEY_UDID = "udid"; private AccountUtils() { } public static void resetBackoff(SharedPreferences prefs) { if (Account.DEBUG) Log.d(TAG, "Resetting backoff"); setBackoff(prefs, Account.DEFAULT_BACKOFF_MS); } private static int getBackoff(SharedPreferences prefs) { return prefs.getInt(Account.BACKOFF_MS, Account.DEFAULT_BACKOFF_MS); } private static void setBackoff(SharedPreferences prefs, int backoff) { SharedPreferences.Editor editor = prefs.edit(); editor.putInt(Account.BACKOFF_MS, backoff); editor.commit(); } public static void scheduleRetry(Context context, SharedPreferences prefs, Intent intent) { int backoffTimeMs = getBackoff(prefs); int nextAttempt = backoffTimeMs / 2 + sRandom.nextInt(backoffTimeMs); if (Account.DEBUG) Log.d(TAG, "Scheduling retry, backoff = " + nextAttempt + " (" + backoffTimeMs + ") for " + intent.getAction()); PendingIntent retryPendingIntent = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); am.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + nextAttempt, retryPendingIntent); if (backoffTimeMs < Account.MAX_BACKOFF_MS) { setBackoff(prefs, backoffTimeMs * 2); } } public static void scheduleAccountPing(Context context, Intent intent) { if (Account.DEBUG) Log.d(TAG, "Scheduling Account ping, starting = " + new Timestamp(SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_DAY) + " interval (" + AlarmManager.INTERVAL_DAY + ")"); PendingIntent reRegisterPendingIntent = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); am.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_DAY, AlarmManager.INTERVAL_DAY, reRegisterPendingIntent); } public static void cancelAccountPing(Context context, Intent intent) { if (Account.DEBUG) Log.d(TAG, "Canceling Account ping"); PendingIntent reRegisterPendingIntent = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); am.cancel(reRegisterPendingIntent); } public static Account getAccountAccount(Context context) { final AccountManager am = AccountManager.get(context); Account[] accounts = am.getAccountsByType(Account.ACCOUNT_TYPE_Account); return accounts.length > 0 ? accounts[0] : null; } public static void showNotification(Context context, int id, Notification notification) { NotificationManager notificationManager = (NotificationManager) context .getSystemService(Context.NOTIFICATION_SERVICE); notificationManager.notify(id, notification); } public static void hideNotification(Context context, int id) { NotificationManager notificationManager = (NotificationManager) context .getSystemService(Context.NOTIFICATION_SERVICE); notificationManager.cancel(id); } public static void showLearnMoreDialog(Activity context) { WebViewDialogFragment.newInstance().setUri(AuthClient.LEARN_MORE_URI).show(context.getFragmentManager(), WebViewDialogFragment.TAG); } public static void tryEnablingWifi(Context context) { WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); if (!wifiManager.isWifiEnabled()) { wifiManager.setWifiEnabled(true); } } private static Intent getWifiSetupIntent(Context context) { Intent intent = new Intent(); intent.addCategory(Intent.CATEGORY_LAUNCHER); intent.setComponent(new ComponentName(Account.WIFI_COMPONENT_PKG, Account.WIFI_COMPONENT_CLASS)); intent.putExtra(Account.EXTRA_FIRST_RUN, true); intent.putExtra(Account.EXTRA_ALLOW_SKIP, false); intent.putExtra(Account.EXTRA_SHOW_BUTTON_BAR, true); intent.putExtra(Account.EXTRA_ONLY_ACCESS_POINTS, true); intent.putExtra(Account.EXTRA_AUTO_FINISH, true); return intent; } public static void launchWifiSetup(Activity context) { AccountUtils.tryEnablingWifi(context); Intent intent = getWifiSetupIntent(context); context.startActivityForResult(intent, Account.REQUEST_CODE_SETUP_WIFI); } public static void launchWifiSetup(Fragment fragment) { final Context context = fragment.getActivity(); AccountUtils.tryEnablingWifi(context); Intent intent = getWifiSetupIntent(context); fragment.startActivityForResult(intent, Account.REQUEST_CODE_SETUP_WIFI); } public static boolean isNetworkConnected(Context context) { ConnectivityManager connectivityManager = (ConnectivityManager) context .getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); return networkInfo != null && networkInfo.isConnected(); } public static boolean isWifiConnected(Context context) { ConnectivityManager connectivityManager = (ConnectivityManager) context .getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo mWifi = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); return mWifi != null && mWifi.isConnected(); } public static boolean hasTelephony(Context context) { PackageManager packageManager = context.getPackageManager(); return packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY); } public static boolean isGSMPhone(Context context) { TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); int phoneType = telephonyManager.getPhoneType(); return phoneType == TelephonyManager.PHONE_TYPE_GSM; } public static boolean isSimMissing(Context context) { TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); int simState = telephonyManager.getSimState(); return simState == TelephonyManager.SIM_STATE_ABSENT || simState == TelephonyManager.SIM_STATE_UNKNOWN; } public static boolean isUnableToModifyAccounts(Context context) { UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); Bundle restrictions = um.getUserRestrictions(); return restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false); } public static String getDisplayVersion() { return SystemProperties.get("ro.cm.display.version"); } public static String getUniqueDeviceId(Context context) { SharedPreferences prefs = context.getSharedPreferences(Account.SETTINGS_PREFERENCES, Context.MODE_PRIVATE); String udid = prefs.getString(KEY_UDID, null); if (udid != null) return udid; String wifiInterface = SystemProperties.get("wifi.interface"); if (wifiInterface != null) { try { List<NetworkInterface> interfaces = Collections.list(NetworkInterface.getNetworkInterfaces()); for (NetworkInterface networkInterface : interfaces) { if (wifiInterface.equals(networkInterface.getDisplayName())) { byte[] mac = networkInterface.getHardwareAddress(); if (mac != null) { StringBuilder buf = new StringBuilder(); for (int i = 0; i < mac.length; i++) buf.append(String.format("%02X:", mac[i])); if (buf.length() > 0) buf.deleteCharAt(buf.length() - 1); if (Account.DEBUG) Log.d(TAG, "using wifi mac for id : " + buf.toString()); return digest(prefs, context.getPackageName() + buf.toString()); } } } } catch (SocketException e) { Log.e(TAG, "Unable to get wifi mac address", e); } } //If we fail, just use android id. return digest(prefs, context.getPackageName() + Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID)); } private static String digest(SharedPreferences prefs, String input) { try { String id = digest("MD5", input); prefs.edit().putString(KEY_UDID, id).commit(); return id; } catch (Exception e) { return null; } } public static byte[] digestBytes(String algorithm, byte[] bytes) { try { MessageDigest md = MessageDigest.getInstance(algorithm); byte[] digest = md.digest(bytes); return digest; } catch (Exception e) { return null; } } public static String digest(String algorithm, String id) { byte[] digestBytes = digestBytes(algorithm, id.getBytes()); return encodeHex(digestBytes).toLowerCase().trim(); } public static String encodeHex(byte[] bytes) { return new String(Hex.encodeHex(bytes)); } public static String encodeHex(BigInteger integer) { return encodeHex(integer.toByteArray()); } public static byte[] decodeHex(String hex) { try { return Hex.decodeHex(hex.toCharArray()); } catch (DecoderException e) { Log.e(TAG, "Unable to decode hex string", e); throw new AssertionError(e); } } public static String getDeviceSalt(AccountManager accountManager, Account account) { if (account == null) { if (Account.DEBUG) Log.d(TAG, "No Account configured!"); return null; } return accountManager.getUserData(account, Account.ACCOUNT_EXTRA_DEVICE_SALT); } public static String getDeviceSalt(Context context) { AccountManager accountManager = (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE); Account account = getAccountAccount(context); return getDeviceSalt(accountManager, account); } public static byte[] getHmacSecret(AccountManager accountManager, Account account) { if (account == null) { if (Account.DEBUG) Log.d(TAG, "No Account configured!"); return null; } return Base64.decode(accountManager.getUserData(account, Account.ACCOUNT_EXTRA_HMAC_SECRET), Base64.NO_WRAP); } public static byte[] getHmacSecret(Context context) { AccountManager accountManager = (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE); Account account = getAccountAccount(context); return getHmacSecret(accountManager, account); } public static void setMinimumAppVersion(Context context, int minimumVersion) { SharedPreferences prefs = context.getSharedPreferences(Account.SETTINGS_PREFERENCES, Context.MODE_PRIVATE); SharedPreferences.Editor editor = prefs.edit(); editor.putInt(Account.MINIMUM_APP_VERSION, minimumVersion); editor.commit(); } public static int getMinimumAppVersion(Context context) { SharedPreferences prefs = context.getSharedPreferences(Account.SETTINGS_PREFERENCES, Context.MODE_PRIVATE); return prefs.getInt(Account.MINIMUM_APP_VERSION, -1); } public static int getApplicationVersion(Context context) { try { PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); return packageInfo.versionCode; } catch (PackageManager.NameNotFoundException e) { throw new RuntimeException("Could not get package name: " + e); } } public static void showIncompatibleVersionNotification(Context context) { Intent intent = new Intent(context, UpdateRequiredActivity.class); PendingIntent contentIntent = PendingIntent.getActivity(context, 0, intent, 0); Notification notification = new Notification.Builder(context) .setContentTitle(context.getText(R.string.Account_update_required_title)) .setContentText(context.getText(R.string.Account_update_required_short)) .setSmallIcon(R.drawable.ic_dialog_alert) .setLargeIcon(((BitmapDrawable) context.getResources().getDrawable(R.drawable.icon)).getBitmap()) .setContentIntent(contentIntent).build(); AccountUtils.showNotification(context, Account.NOTIFICATION_ID_INCOMPATIBLE_VERSION, notification); } }