diff --git a/app/llx/app/src/extreme/java/com/google/android/vending/licensing/AESObfuscator.java b/app/llx/app/src/extreme/java/com/google/android/vending/licensing/AESObfuscator.java index ee12c68..ab8a1d6 100644 --- a/app/llx/app/src/extreme/java/com/google/android/vending/licensing/AESObfuscator.java +++ b/app/llx/app/src/extreme/java/com/google/android/vending/licensing/AESObfuscator.java @@ -19,7 +19,7 @@ package com.google.android.vending.licensing; import com.google.android.vending.licensing.util.Base64; import com.google.android.vending.licensing.util.Base64DecoderException; -import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; import java.security.GeneralSecurityException; import java.security.spec.KeySpec; @@ -40,23 +40,23 @@ public class AESObfuscator implements Obfuscator { private static final String KEYGEN_ALGORITHM = "PBEWITHSHAAND256BITAES-CBC-BC"; private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding"; private static final byte[] IV = - { 16, 74, 71, -80, 32, 101, -47, 72, 117, -14, 0, -29, 70, 65, -12, 74 }; + {16, 74, 71, -80, 32, 101, -47, 72, 117, -14, 0, -29, 70, 65, -12, 74}; private static final String header = "com.android.vending.licensing.AESObfuscator-1|"; - private Cipher mEncryptor; - private Cipher mDecryptor; + private final Cipher mEncryptor; + private final Cipher mDecryptor; /** - * @param salt an array of random bytes to use for each (un)obfuscation + * @param salt an array of random bytes to use for each (un)obfuscation * @param applicationId application identifier, e.g. the package name - * @param deviceId device identifier. Use as many sources as possible to - * create this unique identifier. + * @param deviceId device identifier. Use as many sources as possible to + * create this unique identifier. */ public AESObfuscator(byte[] salt, String applicationId, String deviceId) { try { SecretKeyFactory factory = SecretKeyFactory.getInstance(KEYGEN_ALGORITHM); - KeySpec keySpec = - new PBEKeySpec((applicationId + deviceId).toCharArray(), salt, 1024, 256); + KeySpec keySpec = + new PBEKeySpec((applicationId + deviceId).toCharArray(), salt, 1024, 256); SecretKey tmp = factory.generateSecret(keySpec); SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES"); mEncryptor = Cipher.getInstance(CIPHER_ALGORITHM); @@ -75,9 +75,7 @@ public class AESObfuscator implements Obfuscator { } try { // Header is appended as an integrity check - return Base64.encode(mEncryptor.doFinal((header + key + original).getBytes(UTF8))); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException("Invalid environment", e); + return Base64.encode(mEncryptor.doFinal((header + key + original).getBytes(StandardCharsets.UTF_8))); } catch (GeneralSecurityException e) { throw new RuntimeException("Invalid environment", e); } @@ -88,23 +86,21 @@ public class AESObfuscator implements Obfuscator { return null; } try { - String result = new String(mDecryptor.doFinal(Base64.decode(obfuscated)), UTF8); + String result = new String(mDecryptor.doFinal(Base64.decode(obfuscated)), StandardCharsets.UTF_8); // Check for presence of header. This serves as a final integrity check, for cases // where the block size is correct during decryption. - int headerIndex = result.indexOf(header+key); + int headerIndex = result.indexOf(header + key); if (headerIndex != 0) { throw new ValidationException("Header not found (invalid data or key)" + ":" + obfuscated); } - return result.substring(header.length()+key.length(), result.length()); + return result.substring(header.length() + key.length()); } catch (Base64DecoderException e) { throw new ValidationException(e.getMessage() + ":" + obfuscated); } catch (IllegalBlockSizeException e) { throw new ValidationException(e.getMessage() + ":" + obfuscated); } catch (BadPaddingException e) { throw new ValidationException(e.getMessage() + ":" + obfuscated); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException("Invalid environment", e); } } } diff --git a/app/llx/app/src/extreme/java/com/google/android/vending/licensing/JSONDataObfuscator.java b/app/llx/app/src/extreme/java/com/google/android/vending/licensing/JSONDataObfuscator.java index d9e433e..a6fd638 100644 --- a/app/llx/app/src/extreme/java/com/google/android/vending/licensing/JSONDataObfuscator.java +++ b/app/llx/app/src/extreme/java/com/google/android/vending/licensing/JSONDataObfuscator.java @@ -17,9 +17,7 @@ package com.google.android.vending.licensing; import android.content.Context; -import android.content.SharedPreferences; import android.provider.Settings; -import android.util.Log; import net.pierrox.lightning_launcher.data.FileUtils; @@ -32,15 +30,15 @@ import java.io.IOException; public class JSONDataObfuscator { - private static final byte[] SALT = new byte[] { + private static final byte[] SALT = new byte[]{ 42, 13, 27, -7, 1, 63, -51, 94, 107, 120, 4, -54, -77, 123, -12, -72, -99, 10, 0, 73 }; - private File mFile; - private String mPackageName; - private JSONObject mData; + private final File mFile; + private final String mPackageName; private final Obfuscator mObfuscator; + private JSONObject mData; public JSONDataObfuscator(Context context) { @@ -49,10 +47,10 @@ public class JSONDataObfuscator { mFile = new File(context.getCacheDir(), "icon"); mObfuscator = new AESObfuscator(SALT, mPackageName, deviceId); String obfuscated_data = FileUtils.readFileContent(mFile); - if(obfuscated_data != null) { + if (obfuscated_data != null) { try { String data = mObfuscator.unobfuscate(obfuscated_data, context.getPackageName()); - if(data != null) { + if (data != null) { mData = new JSONObject(data); } } catch (Exception e) { @@ -60,7 +58,7 @@ public class JSONDataObfuscator { } } - if(mData == null) { + if (mData == null) { mData = new JSONObject(); } } diff --git a/app/llx/app/src/extreme/java/com/google/android/vending/licensing/LicenseChecker.java b/app/llx/app/src/extreme/java/com/google/android/vending/licensing/LicenseChecker.java index 6431141..e1fb2f4 100644 --- a/app/llx/app/src/extreme/java/com/google/android/vending/licensing/LicenseChecker.java +++ b/app/llx/app/src/extreme/java/com/google/android/vending/licensing/LicenseChecker.java @@ -16,11 +16,6 @@ package com.google.android.vending.licensing; -import com.android.vending.licensing.ILicenseResultListener; -import com.android.vending.licensing.ILicensingService; -import com.google.android.vending.licensing.util.Base64; -import com.google.android.vending.licensing.util.Base64DecoderException; - import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -31,6 +26,11 @@ import android.os.HandlerThread; import android.os.IBinder; import android.os.RemoteException; +import com.android.vending.licensing.ILicenseResultListener; +import com.android.vending.licensing.ILicensingService; +import com.google.android.vending.licensing.util.Base64; +import com.google.android.vending.licensing.util.Base64DecoderException; + import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; @@ -64,25 +64,23 @@ public class LicenseChecker implements ServiceConnection { private static final SecureRandom RANDOM = new SecureRandom(); private static final boolean DEBUG_LICENSE_ERROR = false; - - private ILicensingService mService; - - private PublicKey mPublicKey; + private final PublicKey mPublicKey; private final Context mContext; private final Policy mPolicy; /** * A handler for running tasks on a background thread. We don't want license * processing to block the UI thread. */ - private Handler mHandler; + private final Handler mHandler; private final String mPackageName; private final String mVersionCode; private final Set mChecksInProgress = new HashSet(); private final Queue mPendingChecks = new LinkedList(); + private ILicensingService mService; /** - * @param context a Context - * @param policy implementation of Policy + * @param context a Context + * @param policy implementation of Policy * @param encodedPublicKey Base64-encoded RSA public key * @throws IllegalArgumentException if encodedPublicKey is invalid */ @@ -100,7 +98,7 @@ public class LicenseChecker implements ServiceConnection { /** * Generates a PublicKey instance from a string containing the * Base64-encoded public key. - * + * * @param encodedPublicKey Base64-encoded public key * @throws IllegalArgumentException if encodedPublicKey is invalid */ @@ -122,6 +120,23 @@ public class LicenseChecker implements ServiceConnection { } } + /** + * Get version code for the application package name. + * + * @param context + * @param packageName application package name + * @return the version code or empty string if package not found + */ + private static String getVersionCode(Context context, String packageName) { + try { + return String.valueOf(context.getPackageManager().getPackageInfo(packageName, 0). + versionCode); + } catch (NameNotFoundException e) { +// Log.e(TAG, "Package not found. could not get version code."); + return ""; + } + } + /** * Checks if the user should have access to the app. Binds the service if necessary. *

@@ -131,6 +146,7 @@ public class LicenseChecker implements ServiceConnection { *

* source string: "com.android.vending.licensing.ILicensingService" *

+ * * @param callback */ public synchronized void checkAccess(LicenseCheckerCallback callback) { @@ -145,8 +161,8 @@ public class LicenseChecker implements ServiceConnection { if (mService == null) { // Log.i(TAG, "Binding to licensing service."); try { - String two = String.valueOf((new Date().getYear()+1900)/1000); - Intent serviceIntent = new Intent(new String(Base64.decode("Y" + two + "9tLmFuZHJvaWQudmVuZGluZy5saWNlbnNpbmcuSUxpY"+two+"Vuc"+two+"luZ1NlcnZpY"+two+"U="))); + String two = String.valueOf((new Date().getYear() + 1900) / 1000); + Intent serviceIntent = new Intent(new String(Base64.decode("Y" + two + "9tLmFuZHJvaWQudmVuZGluZy5saWNlbnNpbmcuSUxpY" + two + "Vuc" + two + "luZ1NlcnZpY" + two + "U="))); serviceIntent.setPackage("com.android.vending"); boolean bindResult = mContext .bindService( @@ -195,10 +211,88 @@ public class LicenseChecker implements ServiceConnection { } } - private class ResultListener extends ILicenseResultListener.Stub { - private final LicenseValidator mValidator; - private Runnable mOnTimeout; + public synchronized void onServiceConnected(ComponentName name, IBinder service) { + mService = ILicensingService.Stub.asInterface(service); + runChecks(); + } + public synchronized void onServiceDisconnected(ComponentName name) { + // Called when the connection with the service has been + // unexpectedly disconnected. That is, Market crashed. + // If there are any checks in progress, the timeouts will handle them. +// Log.w(TAG, "Service unexpectedly disconnected."); + mService = null; + } + + /** + * Generates policy response for service connection errors, as a result of + * disconnections or timeouts. + */ + private synchronized void handleServiceConnectionError(LicenseValidator validator) { + mPolicy.processServerResponse(Policy.RETRY, null); + + if (mPolicy.allowAccess()) { + validator.getCallback().allow(Policy.RETRY); + } else { + validator.getCallback().dontAllow(Policy.RETRY); + } + } + + /** + * Generates policy response for no service connection error (no Google Play service) + */ + private synchronized void handleNoServiceConnectionError(LicenseValidator validator) { + mPolicy.processServerResponse(Policy.NO_SERVICE, null); + + if (mPolicy.allowAccess()) { + validator.getCallback().allow(Policy.NO_SERVICE); + } else { + validator.getCallback().dontAllow(Policy.NO_SERVICE); + } + } + + /** + * Unbinds service if necessary and removes reference to it. + */ + private void cleanupService() { + if (mService != null) { + try { + mContext.unbindService(this); + } catch (IllegalArgumentException e) { + // Somehow we've already been unbound. This is a non-fatal + // error. +// Log.e(TAG, "Unable to unbind from licensing service (already unbound)"); + } + mService = null; + } + } + + /** + * Inform the library that the context is about to be destroyed, so that any + * open connections can be cleaned up. + *

+ * Failure to call this method can result in a crash under certain + * circumstances, such as during screen rotation if an Activity requests the + * license check or when the user exits the application. + */ + public synchronized void onDestroy() { + cleanupService(); + mHandler.getLooper().quit(); + } + + /** + * Generates a nonce (number used once). + */ + private int generateNonce() { + return RANDOM.nextInt(); + } + + private class ResultListener extends ILicenseResultListener.Stub { + private static final int ERROR_CONTACTING_SERVER = 0x101; + private static final int ERROR_INVALID_PACKAGE_NAME = 0x102; + private static final int ERROR_NON_MATCHING_UID = 0x103; + private final LicenseValidator mValidator; + private final Runnable mOnTimeout; public ResultListener(LicenseValidator validator) { mValidator = validator; mOnTimeout = new Runnable() { @@ -211,14 +305,10 @@ public class LicenseChecker implements ServiceConnection { startTimeout(); } - private static final int ERROR_CONTACTING_SERVER = 0x101; - private static final int ERROR_INVALID_PACKAGE_NAME = 0x102; - private static final int ERROR_NON_MATCHING_UID = 0x103; - // Runs in IPC thread pool. Post it to the Handler, so we can guarantee // either this or the timeout runs. public void verifyLicense(final int responseCode, final String signedData, - final String signature) { + final String signature) { mHandler.post(new Runnable() { public void run() { // Log.i(TAG, "Received response."); @@ -272,93 +362,4 @@ public class LicenseChecker implements ServiceConnection { mHandler.removeCallbacks(mOnTimeout); } } - - public synchronized void onServiceConnected(ComponentName name, IBinder service) { - mService = ILicensingService.Stub.asInterface(service); - runChecks(); - } - - public synchronized void onServiceDisconnected(ComponentName name) { - // Called when the connection with the service has been - // unexpectedly disconnected. That is, Market crashed. - // If there are any checks in progress, the timeouts will handle them. -// Log.w(TAG, "Service unexpectedly disconnected."); - mService = null; - } - - /** - * Generates policy response for service connection errors, as a result of - * disconnections or timeouts. - */ - private synchronized void handleServiceConnectionError(LicenseValidator validator) { - mPolicy.processServerResponse(Policy.RETRY, null); - - if (mPolicy.allowAccess()) { - validator.getCallback().allow(Policy.RETRY); - } else { - validator.getCallback().dontAllow(Policy.RETRY); - } - } - - /** - * Generates policy response for no service connection error (no Google Play service) - */ - private synchronized void handleNoServiceConnectionError(LicenseValidator validator) { - mPolicy.processServerResponse(Policy.NO_SERVICE, null); - - if (mPolicy.allowAccess()) { - validator.getCallback().allow(Policy.NO_SERVICE); - } else { - validator.getCallback().dontAllow(Policy.NO_SERVICE); - } - } - - /** Unbinds service if necessary and removes reference to it. */ - private void cleanupService() { - if (mService != null) { - try { - mContext.unbindService(this); - } catch (IllegalArgumentException e) { - // Somehow we've already been unbound. This is a non-fatal - // error. -// Log.e(TAG, "Unable to unbind from licensing service (already unbound)"); - } - mService = null; - } - } - - /** - * Inform the library that the context is about to be destroyed, so that any - * open connections can be cleaned up. - *

- * Failure to call this method can result in a crash under certain - * circumstances, such as during screen rotation if an Activity requests the - * license check or when the user exits the application. - */ - public synchronized void onDestroy() { - cleanupService(); - mHandler.getLooper().quit(); - } - - /** Generates a nonce (number used once). */ - private int generateNonce() { - return RANDOM.nextInt(); - } - - /** - * Get version code for the application package name. - * - * @param context - * @param packageName application package name - * @return the version code or empty string if package not found - */ - private static String getVersionCode(Context context, String packageName) { - try { - return String.valueOf(context.getPackageManager().getPackageInfo(packageName, 0). - versionCode); - } catch (NameNotFoundException e) { -// Log.e(TAG, "Package not found. could not get version code."); - return ""; - } - } } diff --git a/app/llx/app/src/extreme/java/com/google/android/vending/licensing/LicenseCheckerCallback.java b/app/llx/app/src/extreme/java/com/google/android/vending/licensing/LicenseCheckerCallback.java index b250a71..5d96feb 100644 --- a/app/llx/app/src/extreme/java/com/google/android/vending/licensing/LicenseCheckerCallback.java +++ b/app/llx/app/src/extreme/java/com/google/android/vending/licensing/LicenseCheckerCallback.java @@ -35,33 +35,35 @@ package com.google.android.vending.licensing; public interface LicenseCheckerCallback { /** - * Allow use. App should proceed as normal. - * - * @param reason Policy.LICENSED or Policy.RETRY typically. (although in - * theory the policy can return Policy.NOT_LICENSED here as well) + * Application error codes. */ - public void allow(int reason); + int ERROR_INVALID_PACKAGE_NAME = 1; + int ERROR_NON_MATCHING_UID = 2; + int ERROR_NOT_MARKET_MANAGED = 3; + int ERROR_CHECK_IN_PROGRESS = 4; + int ERROR_INVALID_PUBLIC_KEY = 5; + int ERROR_MISSING_PERMISSION = 6; + + /** + * Allow use. App should proceed as normal. + * + * @param reason Policy.LICENSED or Policy.RETRY typically. (although in + * theory the policy can return Policy.NOT_LICENSED here as well) + */ + void allow(int reason); /** * Don't allow use. App should inform user and take appropriate action. - * + * * @param reason Policy.NOT_LICENSED or Policy.RETRY. (although in theory - * the policy can return Policy.LICENSED here as well --- - * perhaps the call to the LVL took too long, for example) + * the policy can return Policy.LICENSED here as well --- + * perhaps the call to the LVL took too long, for example) */ - public void dontAllow(int reason); - - /** Application error codes. */ - public static final int ERROR_INVALID_PACKAGE_NAME = 1; - public static final int ERROR_NON_MATCHING_UID = 2; - public static final int ERROR_NOT_MARKET_MANAGED = 3; - public static final int ERROR_CHECK_IN_PROGRESS = 4; - public static final int ERROR_INVALID_PUBLIC_KEY = 5; - public static final int ERROR_MISSING_PERMISSION = 6; + void dontAllow(int reason); /** * Error in application code. Caller did not call or set up license checker * correctly. Should be considered fatal. */ - public void applicationError(int errorCode); + void applicationError(int errorCode); } diff --git a/app/llx/app/src/extreme/java/com/google/android/vending/licensing/Policy.java b/app/llx/app/src/extreme/java/com/google/android/vending/licensing/Policy.java index c3c9fca..4f961d4 100644 --- a/app/llx/app/src/extreme/java/com/google/android/vending/licensing/Policy.java +++ b/app/llx/app/src/extreme/java/com/google/android/vending/licensing/Policy.java @@ -30,29 +30,29 @@ public interface Policy { /** * LICENSED means that the server returned back a valid license response */ - public static final int LICENSED = 0x16f8e94; + int LICENSED = 0x16f8e94; /** * NOT_LICENSED means that the server returned back a valid license response * that indicated that the user definitively is not licensed */ - public static final int NOT_LICENSED = 0x1; + int NOT_LICENSED = 0x1; /** * RETRY means that the license response was unable to be determined --- * perhaps as a result of faulty networking */ - public static final int RETRY = 0x56ee981; + int RETRY = 0x56ee981; /** * NO_SERVICE means no connection with the Google Play service */ - public static final int NO_SERVICE = 0x936af1; + int NO_SERVICE = 0x936af1; /** * Provide results from contact with the license server. Retry counts are * incremented if the current value of response is RETRY. Results will be * used for any future policy decisions. - * + * * @param response the result from validating the server response - * @param rawData the raw server response data, can be null for RETRY + * @param rawData the raw server response data, can be null for RETRY */ void processServerResponse(int response, ResponseData rawData); diff --git a/app/llx/app/src/extreme/java/com/google/android/vending/licensing/ServerManagedPolicy.java b/app/llx/app/src/extreme/java/com/google/android/vending/licensing/ServerManagedPolicy.java index 5233eb8..c831186 100644 --- a/app/llx/app/src/extreme/java/com/google/android/vending/licensing/ServerManagedPolicy.java +++ b/app/llx/app/src/extreme/java/com/google/android/vending/licensing/ServerManagedPolicy.java @@ -16,17 +16,17 @@ package com.google.android.vending.licensing; +import android.content.Context; + +import com.google.android.vending.licensing.util.Item; +import com.google.android.vending.licensing.util.URLUtils; + import java.net.URI; import java.net.URISyntaxException; import java.util.HashMap; import java.util.List; import java.util.Map; -import android.content.Context; - -import com.google.android.vending.licensing.util.Item; -import com.google.android.vending.licensing.util.URLUtils; - /** * Default policy. All policy decisions are based off of response data received * from the licensing service. Specifically, the licensing server sends the @@ -54,14 +54,13 @@ public class ServerManagedPolicy implements Policy { private static final String DEFAULT_RETRY_COUNT = "5"; private static final long MILLIS_PER_MINUTE = 60 * 1000; - + private final JSONDataObfuscator mPreferences; private long mValidityTimestamp; private long mRetryUntil; private long mMaxRetries; private long mRetryCount; private long mLastResponseTime = 0; private int mLastResponse; - private JSONDataObfuscator mPreferences; public ServerManagedPolicy(Context context) { // Import old values @@ -86,7 +85,7 @@ public class ServerManagedPolicy implements Policy { * * * @param response the result from validating the server response - * @param rawData the raw server response data + * @param rawData the raw server response data */ public void processServerResponse(int response, ResponseData rawData) { @@ -128,6 +127,10 @@ public class ServerManagedPolicy implements Policy { mPreferences.putString(PREF_LAST_RESPONSE, Integer.toString(l)); } + public long getRetryCount() { + return mRetryCount; + } + /** * Set the current retry count and add to preferences. You must manually * call PreferenceObfuscator.commit() to commit these changes to disk. @@ -139,8 +142,8 @@ public class ServerManagedPolicy implements Policy { mPreferences.putString(PREF_RETRY_COUNT, Long.toString(c)); } - public long getRetryCount() { - return mRetryCount; + public long getValidityTimestamp() { + return mValidityTimestamp; } /** @@ -165,8 +168,8 @@ public class ServerManagedPolicy implements Policy { mPreferences.putString(PREF_VALIDITY_TIMESTAMP, validityTimestamp); } - public long getValidityTimestamp() { - return mValidityTimestamp; + public long getRetryUntil() { + return mRetryUntil; } /** @@ -184,15 +187,15 @@ public class ServerManagedPolicy implements Policy { // No response or not parsable, expire immediately // Log.w(TAG, "License retry timestamp (GT) missing, grace period disabled"); retryUntil = "0"; - lRetryUntil = 0l; + lRetryUntil = 0L; } mRetryUntil = lRetryUntil; mPreferences.putString(PREF_RETRY_UNTIL, retryUntil); } - public long getRetryUntil() { - return mRetryUntil; + public long getMaxRetries() { + return mMaxRetries; } /** @@ -210,20 +213,16 @@ public class ServerManagedPolicy implements Policy { // No response or not parsable, expire immediately // Log.w(TAG, "Licence retry count (GR) missing, grace period disabled"); maxRetries = "0"; - lMaxRetries = 0l; + lMaxRetries = 0L; } mMaxRetries = lMaxRetries; mPreferences.putString(PREF_MAX_RETRIES, maxRetries); } - public long getMaxRetries() { - return mMaxRetries; - } - /** * {@inheritDoc} - * + *

* This implementation allows access if either:
*

    *
  1. a LICENSED response was received within the validity period @@ -235,19 +234,14 @@ public class ServerManagedPolicy implements Policy { long ts = System.currentTimeMillis(); if (mLastResponse == Policy.LICENSED) { // Check if the LICENSED response occurred within the validity timeout. - if (ts <= mValidityTimestamp) { - // Cached LICENSED response is still valid. - return true; - } + // Cached LICENSED response is still valid. + return ts <= mValidityTimestamp; } else if (mLastResponse == Policy.RETRY && - ts < mLastResponseTime + MILLIS_PER_MINUTE) { + ts < mLastResponseTime + MILLIS_PER_MINUTE) { // Only allow access if we are within the retry period or we haven't used up our // max retries. return (ts <= mRetryUntil || mRetryCount <= mMaxRetries); - } else if(mLastResponse == Policy.NO_SERVICE) { - return true; - } - return false; + } else return mLastResponse == Policy.NO_SERVICE; } private Map decodeExtras(String extras) { diff --git a/app/llx/app/src/extreme/java/com/google/android/vending/licensing/util/Base64.java b/app/llx/app/src/extreme/java/com/google/android/vending/licensing/util/Base64.java index a0d2779..3fcc1ce 100644 --- a/app/llx/app/src/extreme/java/com/google/android/vending/licensing/util/Base64.java +++ b/app/llx/app/src/extreme/java/com/google/android/vending/licensing/util/Base64.java @@ -39,532 +39,543 @@ package com.google.android.vending.licensing.util; * class. */ public class Base64 { - /** Specify encoding (value is {@code true}). */ - public final static boolean ENCODE = true; + /** + * Specify encoding (value is {@code true}). + */ + public final static boolean ENCODE = true; - /** Specify decoding (value is {@code false}). */ - public final static boolean DECODE = false; + /** + * Specify decoding (value is {@code false}). + */ + public final static boolean DECODE = false; - /** The equals sign (=) as a byte. */ - private final static byte EQUALS_SIGN = (byte) '='; + /** + * The equals sign (=) as a byte. + */ + private final static byte EQUALS_SIGN = (byte) '='; - /** The new line character (\n) as a byte. */ - private final static byte NEW_LINE = (byte) '\n'; + /** + * The new line character (\n) as a byte. + */ + private final static byte NEW_LINE = (byte) '\n'; - /** - * The 64 valid Base64 values. - */ - private final static byte[] ALPHABET = - {(byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', - (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', - (byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', - (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', - (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', - (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', - (byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', - (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o', - (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', - (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', - (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', - (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', - (byte) '9', (byte) '+', (byte) '/'}; + /** + * The 64 valid Base64 values. + */ + private final static byte[] ALPHABET = + {(byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', + (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', + (byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', + (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', + (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', + (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', + (byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', + (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o', + (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', + (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', + (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', + (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', + (byte) '9', (byte) '+', (byte) '/'}; - /** - * The 64 valid web safe Base64 values. - */ - private final static byte[] WEBSAFE_ALPHABET = - {(byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', - (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', - (byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', - (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', - (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', - (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', - (byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', - (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o', - (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', - (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', - (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', - (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', - (byte) '9', (byte) '-', (byte) '_'}; + /** + * The 64 valid web safe Base64 values. + */ + private final static byte[] WEBSAFE_ALPHABET = + {(byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', + (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', + (byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', + (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', + (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', + (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', + (byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', + (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o', + (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', + (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', + (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', + (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', + (byte) '9', (byte) '-', (byte) '_'}; - /** - * Translates a Base64 value to either its 6-bit reconstruction value - * or a negative number indicating some other meaning. - **/ - private final static byte[] DECODABET = {-9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8 - -5, -5, // Whitespace: Tab and Linefeed - -9, -9, // Decimal 11 - 12 - -5, // Whitespace: Carriage Return - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26 - -9, -9, -9, -9, -9, // Decimal 27 - 31 - -5, // Whitespace: Space - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42 - 62, // Plus sign at decimal 43 - -9, -9, -9, // Decimal 44 - 46 - 63, // Slash at decimal 47 - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine - -9, -9, -9, // Decimal 58 - 60 - -1, // Equals sign at decimal 61 - -9, -9, -9, // Decimal 62 - 64 - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N' - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z' - -9, -9, -9, -9, -9, -9, // Decimal 91 - 96 - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm' - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z' - -9, -9, -9, -9, -9 // Decimal 123 - 127 - /* ,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 128 - 139 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ - }; + /** + * Translates a Base64 value to either its 6-bit reconstruction value + * or a negative number indicating some other meaning. + **/ + private final static byte[] DECODABET = {-9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8 + -5, -5, // Whitespace: Tab and Linefeed + -9, -9, // Decimal 11 - 12 + -5, // Whitespace: Carriage Return + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26 + -9, -9, -9, -9, -9, // Decimal 27 - 31 + -5, // Whitespace: Space + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42 + 62, // Plus sign at decimal 43 + -9, -9, -9, // Decimal 44 - 46 + 63, // Slash at decimal 47 + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine + -9, -9, -9, // Decimal 58 - 60 + -1, // Equals sign at decimal 61 + -9, -9, -9, // Decimal 62 - 64 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N' + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z' + -9, -9, -9, -9, -9, -9, // Decimal 91 - 96 + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm' + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z' + -9, -9, -9, -9, -9 // Decimal 123 - 127 + /* ,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 128 - 139 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ + }; - /** The web safe decodabet */ - private final static byte[] WEBSAFE_DECODABET = - {-9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8 - -5, -5, // Whitespace: Tab and Linefeed - -9, -9, // Decimal 11 - 12 - -5, // Whitespace: Carriage Return - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26 - -9, -9, -9, -9, -9, // Decimal 27 - 31 - -5, // Whitespace: Space - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 44 - 62, // Dash '-' sign at decimal 45 - -9, -9, // Decimal 46-47 - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine - -9, -9, -9, // Decimal 58 - 60 - -1, // Equals sign at decimal 61 - -9, -9, -9, // Decimal 62 - 64 - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N' - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z' - -9, -9, -9, -9, // Decimal 91-94 - 63, // Underscore '_' at decimal 95 - -9, // Decimal 96 - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm' - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z' - -9, -9, -9, -9, -9 // Decimal 123 - 127 - /* ,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 128 - 139 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ - }; + /** + * The web safe decodabet + */ + private final static byte[] WEBSAFE_DECODABET = + {-9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8 + -5, -5, // Whitespace: Tab and Linefeed + -9, -9, // Decimal 11 - 12 + -5, // Whitespace: Carriage Return + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26 + -9, -9, -9, -9, -9, // Decimal 27 - 31 + -5, // Whitespace: Space + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 44 + 62, // Dash '-' sign at decimal 45 + -9, -9, // Decimal 46-47 + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine + -9, -9, -9, // Decimal 58 - 60 + -1, // Equals sign at decimal 61 + -9, -9, -9, // Decimal 62 - 64 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N' + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z' + -9, -9, -9, -9, // Decimal 91-94 + 63, // Underscore '_' at decimal 95 + -9, // Decimal 96 + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm' + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z' + -9, -9, -9, -9, -9 // Decimal 123 - 127 + /* ,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 128 - 139 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ + }; - // Indicates white space in encoding - private final static byte WHITE_SPACE_ENC = -5; - // Indicates equals sign in encoding - private final static byte EQUALS_SIGN_ENC = -1; + // Indicates white space in encoding + private final static byte WHITE_SPACE_ENC = -5; + // Indicates equals sign in encoding + private final static byte EQUALS_SIGN_ENC = -1; - /** Defeats instantiation. */ - private Base64() { - } - - /* ******** E N C O D I N G M E T H O D S ******** */ - - /** - * Encodes up to three bytes of the array source - * and writes the resulting four Base64 bytes to destination. - * The source and destination arrays can be manipulated - * anywhere along their length by specifying - * srcOffset and destOffset. - * This method does not check to make sure your arrays - * are large enough to accommodate srcOffset + 3 for - * the source array or destOffset + 4 for - * the destination array. - * The actual number of significant bytes in your array is - * given by numSigBytes. - * - * @param source the array to convert - * @param srcOffset the index where conversion begins - * @param numSigBytes the number of significant bytes in your array - * @param destination the array to hold the conversion - * @param destOffset the index where output will be put - * @param alphabet is the encoding alphabet - * @return the destination array - * @since 1.3 - */ - private static byte[] encode3to4(byte[] source, int srcOffset, - int numSigBytes, byte[] destination, int destOffset, byte[] alphabet) { - // 1 2 3 - // 01234567890123456789012345678901 Bit position - // --------000000001111111122222222 Array position from threeBytes - // --------| || || || | Six bit groups to index alphabet - // >>18 >>12 >> 6 >> 0 Right shift necessary - // 0x3f 0x3f 0x3f Additional AND - - // Create buffer with zero-padding if there are only one or two - // significant bytes passed in the array. - // We have to shift left 24 in order to flush out the 1's that appear - // when Java treats a value as negative that is cast from a byte to an int. - int inBuff = - (numSigBytes > 0 ? ((source[srcOffset] << 24) >>> 8) : 0) - | (numSigBytes > 1 ? ((source[srcOffset + 1] << 24) >>> 16) : 0) - | (numSigBytes > 2 ? ((source[srcOffset + 2] << 24) >>> 24) : 0); - - switch (numSigBytes) { - case 3: - destination[destOffset] = alphabet[(inBuff >>> 18)]; - destination[destOffset + 1] = alphabet[(inBuff >>> 12) & 0x3f]; - destination[destOffset + 2] = alphabet[(inBuff >>> 6) & 0x3f]; - destination[destOffset + 3] = alphabet[(inBuff) & 0x3f]; - return destination; - case 2: - destination[destOffset] = alphabet[(inBuff >>> 18)]; - destination[destOffset + 1] = alphabet[(inBuff >>> 12) & 0x3f]; - destination[destOffset + 2] = alphabet[(inBuff >>> 6) & 0x3f]; - destination[destOffset + 3] = EQUALS_SIGN; - return destination; - case 1: - destination[destOffset] = alphabet[(inBuff >>> 18)]; - destination[destOffset + 1] = alphabet[(inBuff >>> 12) & 0x3f]; - destination[destOffset + 2] = EQUALS_SIGN; - destination[destOffset + 3] = EQUALS_SIGN; - return destination; - default: - return destination; - } // end switch - } // end encode3to4 - - /** - * Encodes a byte array into Base64 notation. - * Equivalent to calling - * {@code encodeBytes(source, 0, source.length)} - * - * @param source The data to convert - * @since 1.4 - */ - public static String encode(byte[] source) { - return encode(source, 0, source.length, ALPHABET, true); - } - - /** - * Encodes a byte array into web safe Base64 notation. - * - * @param source The data to convert - * @param doPadding is {@code true} to pad result with '=' chars - * if it does not fall on 3 byte boundaries - */ - public static String encodeWebSafe(byte[] source, boolean doPadding) { - return encode(source, 0, source.length, WEBSAFE_ALPHABET, doPadding); - } - - /** - * Encodes a byte array into Base64 notation. - * - * @param source The data to convert - * @param off Offset in array where conversion should begin - * @param len Length of data to convert - * @param alphabet is the encoding alphabet - * @param doPadding is {@code true} to pad result with '=' chars - * if it does not fall on 3 byte boundaries - * @since 1.4 - */ - public static String encode(byte[] source, int off, int len, byte[] alphabet, - boolean doPadding) { - byte[] outBuff = encode(source, off, len, alphabet, Integer.MAX_VALUE); - int outLen = outBuff.length; - - // If doPadding is false, set length to truncate '=' - // padding characters - while (doPadding == false && outLen > 0) { - if (outBuff[outLen - 1] != '=') { - break; - } - outLen -= 1; + /** + * Defeats instantiation. + */ + private Base64() { } - return new String(outBuff, 0, outLen); - } + /* ******** E N C O D I N G M E T H O D S ******** */ - /** - * Encodes a byte array into Base64 notation. - * - * @param source The data to convert - * @param off Offset in array where conversion should begin - * @param len Length of data to convert - * @param alphabet is the encoding alphabet - * @param maxLineLength maximum length of one line. - * @return the BASE64-encoded byte array - */ - public static byte[] encode(byte[] source, int off, int len, byte[] alphabet, - int maxLineLength) { - int lenDiv3 = (len + 2) / 3; // ceil(len / 3) - int len43 = lenDiv3 * 4; - byte[] outBuff = new byte[len43 // Main 4:3 - + (len43 / maxLineLength)]; // New lines + /** + * Encodes up to three bytes of the array source + * and writes the resulting four Base64 bytes to destination. + * The source and destination arrays can be manipulated + * anywhere along their length by specifying + * srcOffset and destOffset. + * This method does not check to make sure your arrays + * are large enough to accommodate srcOffset + 3 for + * the source array or destOffset + 4 for + * the destination array. + * The actual number of significant bytes in your array is + * given by numSigBytes. + * + * @param source the array to convert + * @param srcOffset the index where conversion begins + * @param numSigBytes the number of significant bytes in your array + * @param destination the array to hold the conversion + * @param destOffset the index where output will be put + * @param alphabet is the encoding alphabet + * @return the destination array + * @since 1.3 + */ + private static byte[] encode3to4(byte[] source, int srcOffset, + int numSigBytes, byte[] destination, int destOffset, byte[] alphabet) { + // 1 2 3 + // 01234567890123456789012345678901 Bit position + // --------000000001111111122222222 Array position from threeBytes + // --------| || || || | Six bit groups to index alphabet + // >>18 >>12 >> 6 >> 0 Right shift necessary + // 0x3f 0x3f 0x3f Additional AND - int d = 0; - int e = 0; - int len2 = len - 2; - int lineLength = 0; - for (; d < len2; d += 3, e += 4) { + // Create buffer with zero-padding if there are only one or two + // significant bytes passed in the array. + // We have to shift left 24 in order to flush out the 1's that appear + // when Java treats a value as negative that is cast from a byte to an int. + int inBuff = + (numSigBytes > 0 ? ((source[srcOffset] << 24) >>> 8) : 0) + | (numSigBytes > 1 ? ((source[srcOffset + 1] << 24) >>> 16) : 0) + | (numSigBytes > 2 ? ((source[srcOffset + 2] << 24) >>> 24) : 0); - // The following block of code is the same as - // encode3to4( source, d + off, 3, outBuff, e, alphabet ); - // but inlined for faster encoding (~20% improvement) - int inBuff = - ((source[d + off] << 24) >>> 8) - | ((source[d + 1 + off] << 24) >>> 16) - | ((source[d + 2 + off] << 24) >>> 24); - outBuff[e] = alphabet[(inBuff >>> 18)]; - outBuff[e + 1] = alphabet[(inBuff >>> 12) & 0x3f]; - outBuff[e + 2] = alphabet[(inBuff >>> 6) & 0x3f]; - outBuff[e + 3] = alphabet[(inBuff) & 0x3f]; + switch (numSigBytes) { + case 3: + destination[destOffset] = alphabet[(inBuff >>> 18)]; + destination[destOffset + 1] = alphabet[(inBuff >>> 12) & 0x3f]; + destination[destOffset + 2] = alphabet[(inBuff >>> 6) & 0x3f]; + destination[destOffset + 3] = alphabet[(inBuff) & 0x3f]; + return destination; + case 2: + destination[destOffset] = alphabet[(inBuff >>> 18)]; + destination[destOffset + 1] = alphabet[(inBuff >>> 12) & 0x3f]; + destination[destOffset + 2] = alphabet[(inBuff >>> 6) & 0x3f]; + destination[destOffset + 3] = EQUALS_SIGN; + return destination; + case 1: + destination[destOffset] = alphabet[(inBuff >>> 18)]; + destination[destOffset + 1] = alphabet[(inBuff >>> 12) & 0x3f]; + destination[destOffset + 2] = EQUALS_SIGN; + destination[destOffset + 3] = EQUALS_SIGN; + return destination; + default: + return destination; + } // end switch + } // end encode3to4 - lineLength += 4; - if (lineLength == maxLineLength) { - outBuff[e + 4] = NEW_LINE; - e++; - lineLength = 0; - } // end if: end of line - } // end for: each piece of array - - if (d < len) { - encode3to4(source, d + off, len - d, outBuff, e, alphabet); - - lineLength += 4; - if (lineLength == maxLineLength) { - // Add a last newline - outBuff[e + 4] = NEW_LINE; - e++; - } - e += 4; + /** + * Encodes a byte array into Base64 notation. + * Equivalent to calling + * {@code encodeBytes(source, 0, source.length)} + * + * @param source The data to convert + * @since 1.4 + */ + public static String encode(byte[] source) { + return encode(source, 0, source.length, ALPHABET, true); } - assert (e == outBuff.length); - return outBuff; - } - - - /* ******** D E C O D I N G M E T H O D S ******** */ - - - /** - * Decodes four bytes from array source - * and writes the resulting bytes (up to three of them) - * to destination. - * The source and destination arrays can be manipulated - * anywhere along their length by specifying - * srcOffset and destOffset. - * This method does not check to make sure your arrays - * are large enough to accommodate srcOffset + 4 for - * the source array or destOffset + 3 for - * the destination array. - * This method returns the actual number of bytes that - * were converted from the Base64 encoding. - * - * - * @param source the array to convert - * @param srcOffset the index where conversion begins - * @param destination the array to hold the conversion - * @param destOffset the index where output will be put - * @param decodabet the decodabet for decoding Base64 content - * @return the number of decoded bytes converted - * @since 1.3 - */ - private static int decode4to3(byte[] source, int srcOffset, - byte[] destination, int destOffset, byte[] decodabet) { - // Example: Dk== - if (source[srcOffset + 2] == EQUALS_SIGN) { - int outBuff = - ((decodabet[source[srcOffset]] << 24) >>> 6) - | ((decodabet[source[srcOffset + 1]] << 24) >>> 12); - - destination[destOffset] = (byte) (outBuff >>> 16); - return 1; - } else if (source[srcOffset + 3] == EQUALS_SIGN) { - // Example: DkL= - int outBuff = - ((decodabet[source[srcOffset]] << 24) >>> 6) - | ((decodabet[source[srcOffset + 1]] << 24) >>> 12) - | ((decodabet[source[srcOffset + 2]] << 24) >>> 18); - - destination[destOffset] = (byte) (outBuff >>> 16); - destination[destOffset + 1] = (byte) (outBuff >>> 8); - return 2; - } else { - // Example: DkLE - int outBuff = - ((decodabet[source[srcOffset]] << 24) >>> 6) - | ((decodabet[source[srcOffset + 1]] << 24) >>> 12) - | ((decodabet[source[srcOffset + 2]] << 24) >>> 18) - | ((decodabet[source[srcOffset + 3]] << 24) >>> 24); - - destination[destOffset] = (byte) (outBuff >> 16); - destination[destOffset + 1] = (byte) (outBuff >> 8); - destination[destOffset + 2] = (byte) (outBuff); - return 3; + /** + * Encodes a byte array into web safe Base64 notation. + * + * @param source The data to convert + * @param doPadding is {@code true} to pad result with '=' chars + * if it does not fall on 3 byte boundaries + */ + public static String encodeWebSafe(byte[] source, boolean doPadding) { + return encode(source, 0, source.length, WEBSAFE_ALPHABET, doPadding); } - } // end decodeToBytes + /** + * Encodes a byte array into Base64 notation. + * + * @param source The data to convert + * @param off Offset in array where conversion should begin + * @param len Length of data to convert + * @param alphabet is the encoding alphabet + * @param doPadding is {@code true} to pad result with '=' chars + * if it does not fall on 3 byte boundaries + * @since 1.4 + */ + public static String encode(byte[] source, int off, int len, byte[] alphabet, + boolean doPadding) { + byte[] outBuff = encode(source, off, len, alphabet, Integer.MAX_VALUE); + int outLen = outBuff.length; - /** - * Decodes data from Base64 notation. - * - * @param s the string to decode (decoded in default encoding) - * @return the decoded data - * @since 1.4 - */ - public static byte[] decode(String s) throws Base64DecoderException { - byte[] bytes = s.getBytes(); - return decode(bytes, 0, bytes.length); - } - - /** - * Decodes data from web safe Base64 notation. - * Web safe encoding uses '-' instead of '+', '_' instead of '/' - * - * @param s the string to decode (decoded in default encoding) - * @return the decoded data - */ - public static byte[] decodeWebSafe(String s) throws Base64DecoderException { - byte[] bytes = s.getBytes(); - return decodeWebSafe(bytes, 0, bytes.length); - } - - /** - * Decodes Base64 content in byte array format and returns - * the decoded byte array. - * - * @param source The Base64 encoded data - * @return decoded data - * @since 1.3 - * @throws Base64DecoderException - */ - public static byte[] decode(byte[] source) throws Base64DecoderException { - return decode(source, 0, source.length); - } - - /** - * Decodes web safe Base64 content in byte array format and returns - * the decoded data. - * Web safe encoding uses '-' instead of '+', '_' instead of '/' - * - * @param source the string to decode (decoded in default encoding) - * @return the decoded data - */ - public static byte[] decodeWebSafe(byte[] source) - throws Base64DecoderException { - return decodeWebSafe(source, 0, source.length); - } - - /** - * Decodes Base64 content in byte array format and returns - * the decoded byte array. - * - * @param source The Base64 encoded data - * @param off The offset of where to begin decoding - * @param len The length of characters to decode - * @return decoded data - * @since 1.3 - * @throws Base64DecoderException - */ - public static byte[] decode(byte[] source, int off, int len) - throws Base64DecoderException { - return decode(source, off, len, DECODABET); - } - - /** - * Decodes web safe Base64 content in byte array format and returns - * the decoded byte array. - * Web safe encoding uses '-' instead of '+', '_' instead of '/' - * - * @param source The Base64 encoded data - * @param off The offset of where to begin decoding - * @param len The length of characters to decode - * @return decoded data - */ - public static byte[] decodeWebSafe(byte[] source, int off, int len) - throws Base64DecoderException { - return decode(source, off, len, WEBSAFE_DECODABET); - } - - /** - * Decodes Base64 content using the supplied decodabet and returns - * the decoded byte array. - * - * @param source The Base64 encoded data - * @param off The offset of where to begin decoding - * @param len The length of characters to decode - * @param decodabet the decodabet for decoding Base64 content - * @return decoded data - */ - public static byte[] decode(byte[] source, int off, int len, byte[] decodabet) - throws Base64DecoderException { - int len34 = len * 3 / 4; - byte[] outBuff = new byte[2 + len34]; // Upper limit on size of output - int outBuffPosn = 0; - - byte[] b4 = new byte[4]; - int b4Posn = 0; - int i = 0; - byte sbiCrop = 0; - byte sbiDecode = 0; - for (i = 0; i < len; i++) { - sbiCrop = (byte) (source[i + off] & 0x7f); // Only the low seven bits - sbiDecode = decodabet[sbiCrop]; - - if (sbiDecode >= WHITE_SPACE_ENC) { // White space Equals sign or better - if (sbiDecode >= EQUALS_SIGN_ENC) { - // An equals sign (for padding) must not occur at position 0 or 1 - // and must be the last byte[s] in the encoded value - if (sbiCrop == EQUALS_SIGN) { - int bytesLeft = len - i; - byte lastByte = (byte) (source[len - 1 + off] & 0x7f); - if (b4Posn == 0 || b4Posn == 1) { - throw new Base64DecoderException( - "invalid padding byte '=' at byte offset " + i); - } else if ((b4Posn == 3 && bytesLeft > 2) - || (b4Posn == 4 && bytesLeft > 1)) { - throw new Base64DecoderException( - "padding byte '=' falsely signals end of encoded value " - + "at offset " + i); - } else if (lastByte != EQUALS_SIGN && lastByte != NEW_LINE) { - throw new Base64DecoderException( - "encoded value has invalid trailing byte"); + // If doPadding is false, set length to truncate '=' + // padding characters + while (!doPadding && outLen > 0) { + if (outBuff[outLen - 1] != '=') { + break; } - break; - } - - b4[b4Posn++] = sbiCrop; - if (b4Posn == 4) { - outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn, decodabet); - b4Posn = 0; - } + outLen -= 1; } - } else { - throw new Base64DecoderException("Bad Base64 input character at " + i - + ": " + source[i + off] + "(decimal)"); - } + + return new String(outBuff, 0, outLen); } - // Because web safe encoding allows non padding base64 encodes, we - // need to pad the rest of the b4 buffer with equal signs when - // b4Posn != 0. There can be at most 2 equal signs at the end of - // four characters, so the b4 buffer must have two or three - // characters. This also catches the case where the input is - // padded with EQUALS_SIGN - if (b4Posn != 0) { - if (b4Posn == 1) { - throw new Base64DecoderException("single trailing character at offset " - + (len - 1)); - } - b4[b4Posn++] = EQUALS_SIGN; - outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn, decodabet); + /** + * Encodes a byte array into Base64 notation. + * + * @param source The data to convert + * @param off Offset in array where conversion should begin + * @param len Length of data to convert + * @param alphabet is the encoding alphabet + * @param maxLineLength maximum length of one line. + * @return the BASE64-encoded byte array + */ + public static byte[] encode(byte[] source, int off, int len, byte[] alphabet, + int maxLineLength) { + int lenDiv3 = (len + 2) / 3; // ceil(len / 3) + int len43 = lenDiv3 * 4; + byte[] outBuff = new byte[len43 // Main 4:3 + + (len43 / maxLineLength)]; // New lines + + int d = 0; + int e = 0; + int len2 = len - 2; + int lineLength = 0; + for (; d < len2; d += 3, e += 4) { + + // The following block of code is the same as + // encode3to4( source, d + off, 3, outBuff, e, alphabet ); + // but inlined for faster encoding (~20% improvement) + int inBuff = + ((source[d + off] << 24) >>> 8) + | ((source[d + 1 + off] << 24) >>> 16) + | ((source[d + 2 + off] << 24) >>> 24); + outBuff[e] = alphabet[(inBuff >>> 18)]; + outBuff[e + 1] = alphabet[(inBuff >>> 12) & 0x3f]; + outBuff[e + 2] = alphabet[(inBuff >>> 6) & 0x3f]; + outBuff[e + 3] = alphabet[(inBuff) & 0x3f]; + + lineLength += 4; + if (lineLength == maxLineLength) { + outBuff[e + 4] = NEW_LINE; + e++; + lineLength = 0; + } // end if: end of line + } // end for: each piece of array + + if (d < len) { + encode3to4(source, d + off, len - d, outBuff, e, alphabet); + + lineLength += 4; + if (lineLength == maxLineLength) { + // Add a last newline + outBuff[e + 4] = NEW_LINE; + e++; + } + e += 4; + } + + assert (e == outBuff.length); + return outBuff; } - byte[] out = new byte[outBuffPosn]; - System.arraycopy(outBuff, 0, out, 0, outBuffPosn); - return out; - } + + /* ******** D E C O D I N G M E T H O D S ******** */ + + + /** + * Decodes four bytes from array source + * and writes the resulting bytes (up to three of them) + * to destination. + * The source and destination arrays can be manipulated + * anywhere along their length by specifying + * srcOffset and destOffset. + * This method does not check to make sure your arrays + * are large enough to accommodate srcOffset + 4 for + * the source array or destOffset + 3 for + * the destination array. + * This method returns the actual number of bytes that + * were converted from the Base64 encoding. + * + * @param source the array to convert + * @param srcOffset the index where conversion begins + * @param destination the array to hold the conversion + * @param destOffset the index where output will be put + * @param decodabet the decodabet for decoding Base64 content + * @return the number of decoded bytes converted + * @since 1.3 + */ + private static int decode4to3(byte[] source, int srcOffset, + byte[] destination, int destOffset, byte[] decodabet) { + // Example: Dk== + if (source[srcOffset + 2] == EQUALS_SIGN) { + int outBuff = + ((decodabet[source[srcOffset]] << 24) >>> 6) + | ((decodabet[source[srcOffset + 1]] << 24) >>> 12); + + destination[destOffset] = (byte) (outBuff >>> 16); + return 1; + } else if (source[srcOffset + 3] == EQUALS_SIGN) { + // Example: DkL= + int outBuff = + ((decodabet[source[srcOffset]] << 24) >>> 6) + | ((decodabet[source[srcOffset + 1]] << 24) >>> 12) + | ((decodabet[source[srcOffset + 2]] << 24) >>> 18); + + destination[destOffset] = (byte) (outBuff >>> 16); + destination[destOffset + 1] = (byte) (outBuff >>> 8); + return 2; + } else { + // Example: DkLE + int outBuff = + ((decodabet[source[srcOffset]] << 24) >>> 6) + | ((decodabet[source[srcOffset + 1]] << 24) >>> 12) + | ((decodabet[source[srcOffset + 2]] << 24) >>> 18) + | ((decodabet[source[srcOffset + 3]] << 24) >>> 24); + + destination[destOffset] = (byte) (outBuff >> 16); + destination[destOffset + 1] = (byte) (outBuff >> 8); + destination[destOffset + 2] = (byte) (outBuff); + return 3; + } + } // end decodeToBytes + + + /** + * Decodes data from Base64 notation. + * + * @param s the string to decode (decoded in default encoding) + * @return the decoded data + * @since 1.4 + */ + public static byte[] decode(String s) throws Base64DecoderException { + byte[] bytes = s.getBytes(); + return decode(bytes, 0, bytes.length); + } + + /** + * Decodes data from web safe Base64 notation. + * Web safe encoding uses '-' instead of '+', '_' instead of '/' + * + * @param s the string to decode (decoded in default encoding) + * @return the decoded data + */ + public static byte[] decodeWebSafe(String s) throws Base64DecoderException { + byte[] bytes = s.getBytes(); + return decodeWebSafe(bytes, 0, bytes.length); + } + + /** + * Decodes Base64 content in byte array format and returns + * the decoded byte array. + * + * @param source The Base64 encoded data + * @return decoded data + * @throws Base64DecoderException + * @since 1.3 + */ + public static byte[] decode(byte[] source) throws Base64DecoderException { + return decode(source, 0, source.length); + } + + /** + * Decodes web safe Base64 content in byte array format and returns + * the decoded data. + * Web safe encoding uses '-' instead of '+', '_' instead of '/' + * + * @param source the string to decode (decoded in default encoding) + * @return the decoded data + */ + public static byte[] decodeWebSafe(byte[] source) + throws Base64DecoderException { + return decodeWebSafe(source, 0, source.length); + } + + /** + * Decodes Base64 content in byte array format and returns + * the decoded byte array. + * + * @param source The Base64 encoded data + * @param off The offset of where to begin decoding + * @param len The length of characters to decode + * @return decoded data + * @throws Base64DecoderException + * @since 1.3 + */ + public static byte[] decode(byte[] source, int off, int len) + throws Base64DecoderException { + return decode(source, off, len, DECODABET); + } + + /** + * Decodes web safe Base64 content in byte array format and returns + * the decoded byte array. + * Web safe encoding uses '-' instead of '+', '_' instead of '/' + * + * @param source The Base64 encoded data + * @param off The offset of where to begin decoding + * @param len The length of characters to decode + * @return decoded data + */ + public static byte[] decodeWebSafe(byte[] source, int off, int len) + throws Base64DecoderException { + return decode(source, off, len, WEBSAFE_DECODABET); + } + + /** + * Decodes Base64 content using the supplied decodabet and returns + * the decoded byte array. + * + * @param source The Base64 encoded data + * @param off The offset of where to begin decoding + * @param len The length of characters to decode + * @param decodabet the decodabet for decoding Base64 content + * @return decoded data + */ + public static byte[] decode(byte[] source, int off, int len, byte[] decodabet) + throws Base64DecoderException { + int len34 = len * 3 / 4; + byte[] outBuff = new byte[2 + len34]; // Upper limit on size of output + int outBuffPosn = 0; + + byte[] b4 = new byte[4]; + int b4Posn = 0; + int i = 0; + byte sbiCrop = 0; + byte sbiDecode = 0; + for (i = 0; i < len; i++) { + sbiCrop = (byte) (source[i + off] & 0x7f); // Only the low seven bits + sbiDecode = decodabet[sbiCrop]; + + if (sbiDecode >= WHITE_SPACE_ENC) { // White space Equals sign or better + if (sbiDecode >= EQUALS_SIGN_ENC) { + // An equals sign (for padding) must not occur at position 0 or 1 + // and must be the last byte[s] in the encoded value + if (sbiCrop == EQUALS_SIGN) { + int bytesLeft = len - i; + byte lastByte = (byte) (source[len - 1 + off] & 0x7f); + if (b4Posn == 0 || b4Posn == 1) { + throw new Base64DecoderException( + "invalid padding byte '=' at byte offset " + i); + } else if ((b4Posn == 3 && bytesLeft > 2) + || (b4Posn == 4 && bytesLeft > 1)) { + throw new Base64DecoderException( + "padding byte '=' falsely signals end of encoded value " + + "at offset " + i); + } else if (lastByte != EQUALS_SIGN && lastByte != NEW_LINE) { + throw new Base64DecoderException( + "encoded value has invalid trailing byte"); + } + break; + } + + b4[b4Posn++] = sbiCrop; + if (b4Posn == 4) { + outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn, decodabet); + b4Posn = 0; + } + } + } else { + throw new Base64DecoderException("Bad Base64 input character at " + i + + ": " + source[i + off] + "(decimal)"); + } + } + + // Because web safe encoding allows non padding base64 encodes, we + // need to pad the rest of the b4 buffer with equal signs when + // b4Posn != 0. There can be at most 2 equal signs at the end of + // four characters, so the b4 buffer must have two or three + // characters. This also catches the case where the input is + // padded with EQUALS_SIGN + if (b4Posn != 0) { + if (b4Posn == 1) { + throw new Base64DecoderException("single trailing character at offset " + + (len - 1)); + } + b4[b4Posn++] = EQUALS_SIGN; + outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn, decodabet); + } + + byte[] out = new byte[outBuffPosn]; + System.arraycopy(outBuff, 0, out, 0, outBuffPosn); + return out; + } } diff --git a/app/llx/app/src/extreme/java/com/google/android/vending/licensing/util/Item.java b/app/llx/app/src/extreme/java/com/google/android/vending/licensing/util/Item.java index 5f67c66..36170f2 100644 --- a/app/llx/app/src/extreme/java/com/google/android/vending/licensing/util/Item.java +++ b/app/llx/app/src/extreme/java/com/google/android/vending/licensing/util/Item.java @@ -1,8 +1,8 @@ package com.google.android.vending.licensing.util; public class Item { - private String name; - private String value; + private final String name; + private final String value; public Item(String n, String v) { name = n; diff --git a/app/llx/app/src/extreme/java/net/pierrox/lightning_launcher/LLAppExtreme.java b/app/llx/app/src/extreme/java/net/pierrox/lightning_launcher/LLAppExtreme.java index dcc0ad5..2a96528 100644 --- a/app/llx/app/src/extreme/java/net/pierrox/lightning_launcher/LLAppExtreme.java +++ b/app/llx/app/src/extreme/java/net/pierrox/lightning_launcher/LLAppExtreme.java @@ -33,7 +33,6 @@ import android.content.pm.PackageManager; import android.database.Cursor; import android.net.Uri; import android.os.AsyncTask; -import android.os.Handler; import android.os.Process; import android.view.View; import android.widget.Toast; @@ -43,15 +42,15 @@ import com.google.android.vending.licensing.LicenseCheckerCallback; import com.google.android.vending.licensing.Policy; import com.google.android.vending.licensing.ServerManagedPolicy; -import net.pierrox.lightning_launcher.engine.LightningEngine; -import net.pierrox.lightning_launcher_extreme.R; import net.pierrox.lightning_launcher.data.FileUtils; import net.pierrox.lightning_launcher.data.Page; +import net.pierrox.lightning_launcher.engine.LightningEngine; import net.pierrox.lightning_launcher.iab.IabHelper; import net.pierrox.lightning_launcher.iab.IabResult; import net.pierrox.lightning_launcher.iab.Inventory; import net.pierrox.lightning_launcher.iab.Purchase; import net.pierrox.lightning_launcher.prefs.LLPreference; +import net.pierrox.lightning_launcher_extreme.R; import org.json.JSONException; import org.json.JSONObject; @@ -67,11 +66,12 @@ public class LLAppExtreme extends LLAppPhone { private static final String key4 = "hI3T9SPxlX4faIxSX0hwLJAtbb5IZWX5XvuQdQovF9W9"; private static final String key5 = "vRdURFT6D7K01k+doWbMDZnbfQXiYKHaaBja+SlsZA4UsHF6RubVTi+nOET1xBlpjNwQ6wl69GdM+y8WA1WR47JBNph6wuCF0q7pz2KbuBDvh5vSvYaBGb9dflqnOKy2S47DSA7HOwffTUtxilskp"; private static final String key6 = "JvKKBdyKwQoNTKyp7bjXUrFg/tlJOTo0je4RkcvBHiYCW/yEQKSPY43nlnapcy6L4P+0IV+GDHI+Zx1D+mPo6BmsTwIDAQAB"; - + private static final String LWP_PKG = "net.pierrox.lightning_launcher.lwp_key"; + private static final String PATH_TEST = "t"; + private static final String COLUMN_IS_LICENSED = "l"; private LicenseCheckerCallback mLicenseCheckerCallback; private LicenseChecker mChecker; private boolean mIsLicensed = true; - private IabHelper mIABHelper; private String mIabKey; private boolean mHasLWPIab; @@ -80,12 +80,12 @@ public class LLAppExtreme extends LLAppPhone { @Override public void onCreate() { // obfuscation - String three = String.valueOf((new Date().getYear()+2901)/1000); + String three = String.valueOf((new Date().getYear() + 2901) / 1000); mIabKey = key1 + three + key2; mLicenseCheckerCallback = new MyLicenseCheckerCallback(); - mIabKey += three + key3 + three + key4 + getString(R.string.internal_version); + mIabKey += three + key3 + three + key4 + getString(R.string.internal_version); // obfuscation mIabKey += key5 + three + key6; @@ -148,7 +148,7 @@ public class LLAppExtreme extends LLAppPhone { Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(Version.APP_STORE_INSTALL_PREFIX + context.getPackageName())); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); - } catch(ActivityNotFoundException e) { + } catch (ActivityNotFoundException e) { // pass } Toast.makeText(context, "Couldn't validate the Play Store license. Please check your internet connectivity.", Toast.LENGTH_LONG).show(); @@ -171,33 +171,6 @@ public class LLAppExtreme extends LLAppPhone { mChecker.checkAccess(mLicenseCheckerCallback); } - private class MyLicenseCheckerCallback implements LicenseCheckerCallback { - public void allow(int reason) { - mIsLicensed = true; - } - - public void dontAllow(int reason) { - - if (reason == Policy.RETRY) { - // If the reason received from the policy is RETRY, it was probably - // due to a loss of connection with the service, so we should give the - // user a chance to retry. So show a dialog to retry. - mIsLicensed = true; - } else { - // Otherwise, the user is not licensed to use this app. - // Your response should always inform the user that the application - // is not licensed, but your behavior at that point can vary. You might - // provide the user a limited access version of your app or you can - // take them to Google Play to purchase the app. - mIsLicensed = false; - } - } - - @Override - public void applicationError(int errorCode) { - } - } - public String getIabKey() { return mIabKey; } @@ -221,28 +194,24 @@ public class LLAppExtreme extends LLAppPhone { }); } - private static final String LWP_PKG = "net.pierrox.lightning_launcher.lwp_key"; - private static final String PATH_TEST = "t"; - private static final String COLUMN_IS_LICENSED = "l"; - public void checkLwpKey() { // first step : the permission is granted meaning the package is installed mHasLWPKey = checkPermission(LWP_PKG, Process.myPid(), Process.myUid()) == PackageManager.PERMISSION_GRANTED; // second step, ask the key to check its license - new AsyncTask() { + new AsyncTask() { @Override protected Boolean doInBackground(Void... voids) { boolean hasLicensedKey = false; try { - Cursor c = getContentResolver().query(Uri.parse("content://"+LWP_PKG+"/" + PATH_TEST), new String[]{COLUMN_IS_LICENSED}, null, null, null); + Cursor c = getContentResolver().query(Uri.parse("content://" + LWP_PKG + "/" + PATH_TEST), new String[]{COLUMN_IS_LICENSED}, null, null, null); if (c != null) { c.moveToNext(); hasLicensedKey = c.getInt(0) == 1; c.close(); } - } catch(Exception e) { + } catch (Exception e) { // pass } return hasLicensedKey; @@ -251,14 +220,14 @@ public class LLAppExtreme extends LLAppPhone { @Override protected void onPostExecute(Boolean hasLicensedKey) { // key is installed, but no license - if(mHasLWPKey && !hasLicensedKey) { + if (mHasLWPKey && !hasLicensedKey) { LightningEngine engine = getAppEngine(); engine.getGlobalConfig().lwpScreen = Page.NONE; engine.notifyGlobalConfigChanged(); } mHasLWPKey = hasLicensedKey; } - }.execute((Void)null); + }.execute((Void) null); } @@ -271,12 +240,12 @@ public class LLAppExtreme extends LLAppPhone { mHasLWPIab = false; - if(data.exists()) { + if (data.exists()) { JSONObject o = FileUtils.readJSONObjectFromFile(data); - if(o != null) { + if (o != null) { try { mHasLWPIab = o.getBoolean(getString(R.string.iab_lwp)); - } catch(JSONException e) { + } catch (JSONException e) { // pass } } @@ -284,7 +253,7 @@ public class LLAppExtreme extends LLAppPhone { } public void setProductStatus(String sku, boolean purchased) { - if(sku.equals(getString(R.string.iab_lwp))) { + if (sku.equals(getString(R.string.iab_lwp))) { mHasLWPIab = purchased; } File data = getUnlockInfoDataFile(); @@ -297,10 +266,6 @@ public class LLAppExtreme extends LLAppPhone { } } - public interface UnlockResultReceiver { - void setUnlocked(String sku, boolean unlocked); - } - public void checkProducts(final UnlockResultReceiver receiver) { // Have we been disposed of in the meantime? If so, quit. if (mIABHelper == null || !mIABHelper.isSetupDone()) return; @@ -318,12 +283,12 @@ public class LLAppExtreme extends LLAppPhone { Purchase lwp = inventory.getPurchase(iab_lwp); boolean has_lwp = lwp != null /*&& verifyDeveloperPayload(unlock_pro)*/; - if(has_lwp) { + if (has_lwp) { setProductStatus(iab_lwp, true); - if(receiver != null) receiver.setUnlocked(iab_lwp, true); + if (receiver != null) receiver.setUnlocked(iab_lwp, true); } else { setProductStatus(iab_lwp, false); - if(receiver != null) receiver.setUnlocked(iab_lwp, false); + if (receiver != null) receiver.setUnlocked(iab_lwp, false); } } }); @@ -341,7 +306,7 @@ public class LLAppExtreme extends LLAppPhone { builder.setPositiveButton(context.getString(R.string.iab_y_key), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - context.startActivity(Intent.createChooser(new Intent(Intent.ACTION_VIEW, Uri.parse(Version.APP_STORE_INSTALL_PREFIX+"net.pierrox.lightning_launcher.lwp_key")), "")); + context.startActivity(Intent.createChooser(new Intent(Intent.ACTION_VIEW, Uri.parse(Version.APP_STORE_INSTALL_PREFIX + "net.pierrox.lightning_launcher.lwp_key")), "")); } }); builder.setNegativeButton(context.getString(R.string.iab_y_app), new DialogInterface.OnClickListener() { @@ -357,4 +322,31 @@ public class LLAppExtreme extends LLAppPhone { private void startPurchaseProcess(Context context, String sku) { PurchaseProcess.startActivity(context, sku); } + + public interface UnlockResultReceiver { + void setUnlocked(String sku, boolean unlocked); + } + + private class MyLicenseCheckerCallback implements LicenseCheckerCallback { + public void allow(int reason) { + mIsLicensed = true; + } + + public void dontAllow(int reason) { + + // If the reason received from the policy is RETRY, it was probably + // due to a loss of connection with the service, so we should give the + // user a chance to retry. So show a dialog to retry. + // Otherwise, the user is not licensed to use this app. + // Your response should always inform the user that the application + // is not licensed, but your behavior at that point can vary. You might + // provide the user a limited access version of your app or you can + // take them to Google Play to purchase the app. + mIsLicensed = reason == Policy.RETRY; + } + + @Override + public void applicationError(int errorCode) { + } + } } diff --git a/app/llx/app/src/extreme/java/net/pierrox/lightning_launcher/iab/Base64.java b/app/llx/app/src/extreme/java/net/pierrox/lightning_launcher/iab/Base64.java index 494c491..6fae1ed 100644 --- a/app/llx/app/src/extreme/java/net/pierrox/lightning_launcher/iab/Base64.java +++ b/app/llx/app/src/extreme/java/net/pierrox/lightning_launcher/iab/Base64.java @@ -39,133 +39,145 @@ package net.pierrox.lightning_launcher.iab; * class. */ public class Base64 { - /** Specify encoding (value is {@code true}). */ + /** + * Specify encoding (value is {@code true}). + */ public final static boolean ENCODE = true; - /** Specify decoding (value is {@code false}). */ + /** + * Specify decoding (value is {@code false}). + */ public final static boolean DECODE = false; - /** The equals sign (=) as a byte. */ + /** + * The equals sign (=) as a byte. + */ private final static byte EQUALS_SIGN = (byte) '='; - /** The new line character (\n) as a byte. */ + /** + * The new line character (\n) as a byte. + */ private final static byte NEW_LINE = (byte) '\n'; /** * The 64 valid Base64 values. */ private final static byte[] ALPHABET = - {(byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', - (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', - (byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', - (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', - (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', - (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', - (byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', - (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o', - (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', - (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', - (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', - (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', - (byte) '9', (byte) '+', (byte) '/'}; + {(byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', + (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', + (byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', + (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', + (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', + (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', + (byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', + (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o', + (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', + (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', + (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', + (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', + (byte) '9', (byte) '+', (byte) '/'}; /** * The 64 valid web safe Base64 values. */ private final static byte[] WEBSAFE_ALPHABET = - {(byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', - (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', - (byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', - (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', - (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', - (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', - (byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', - (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o', - (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', - (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', - (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', - (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', - (byte) '9', (byte) '-', (byte) '_'}; + {(byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', + (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', + (byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', + (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', + (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', + (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', + (byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', + (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o', + (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', + (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', + (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', + (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', + (byte) '9', (byte) '-', (byte) '_'}; /** * Translates a Base64 value to either its 6-bit reconstruction value * or a negative number indicating some other meaning. **/ private final static byte[] DECODABET = {-9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8 - -5, -5, // Whitespace: Tab and Linefeed - -9, -9, // Decimal 11 - 12 - -5, // Whitespace: Carriage Return - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26 - -9, -9, -9, -9, -9, // Decimal 27 - 31 - -5, // Whitespace: Space - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42 - 62, // Plus sign at decimal 43 - -9, -9, -9, // Decimal 44 - 46 - 63, // Slash at decimal 47 - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine - -9, -9, -9, // Decimal 58 - 60 - -1, // Equals sign at decimal 61 - -9, -9, -9, // Decimal 62 - 64 - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N' - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z' - -9, -9, -9, -9, -9, -9, // Decimal 91 - 96 - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm' - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z' - -9, -9, -9, -9, -9 // Decimal 123 - 127 - /* ,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 128 - 139 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ + -5, -5, // Whitespace: Tab and Linefeed + -9, -9, // Decimal 11 - 12 + -5, // Whitespace: Carriage Return + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26 + -9, -9, -9, -9, -9, // Decimal 27 - 31 + -5, // Whitespace: Space + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42 + 62, // Plus sign at decimal 43 + -9, -9, -9, // Decimal 44 - 46 + 63, // Slash at decimal 47 + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine + -9, -9, -9, // Decimal 58 - 60 + -1, // Equals sign at decimal 61 + -9, -9, -9, // Decimal 62 - 64 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N' + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z' + -9, -9, -9, -9, -9, -9, // Decimal 91 - 96 + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm' + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z' + -9, -9, -9, -9, -9 // Decimal 123 - 127 + /* ,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 128 - 139 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ }; - /** The web safe decodabet */ + /** + * The web safe decodabet + */ private final static byte[] WEBSAFE_DECODABET = - {-9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8 - -5, -5, // Whitespace: Tab and Linefeed - -9, -9, // Decimal 11 - 12 - -5, // Whitespace: Carriage Return - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26 - -9, -9, -9, -9, -9, // Decimal 27 - 31 - -5, // Whitespace: Space - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 44 - 62, // Dash '-' sign at decimal 45 - -9, -9, // Decimal 46-47 - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine - -9, -9, -9, // Decimal 58 - 60 - -1, // Equals sign at decimal 61 - -9, -9, -9, // Decimal 62 - 64 - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N' - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z' - -9, -9, -9, -9, // Decimal 91-94 - 63, // Underscore '_' at decimal 95 - -9, // Decimal 96 - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm' - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z' - -9, -9, -9, -9, -9 // Decimal 123 - 127 - /* ,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 128 - 139 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ - }; + {-9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8 + -5, -5, // Whitespace: Tab and Linefeed + -9, -9, // Decimal 11 - 12 + -5, // Whitespace: Carriage Return + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26 + -9, -9, -9, -9, -9, // Decimal 27 - 31 + -5, // Whitespace: Space + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 44 + 62, // Dash '-' sign at decimal 45 + -9, -9, // Decimal 46-47 + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine + -9, -9, -9, // Decimal 58 - 60 + -1, // Equals sign at decimal 61 + -9, -9, -9, // Decimal 62 - 64 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N' + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z' + -9, -9, -9, -9, // Decimal 91-94 + 63, // Underscore '_' at decimal 95 + -9, // Decimal 96 + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm' + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z' + -9, -9, -9, -9, -9 // Decimal 123 - 127 + /* ,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 128 - 139 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ + }; // Indicates white space in encoding private final static byte WHITE_SPACE_ENC = -5; // Indicates equals sign in encoding private final static byte EQUALS_SIGN_ENC = -1; - /** Defeats instantiation. */ + /** + * Defeats instantiation. + */ private Base64() { } @@ -184,17 +196,17 @@ public class Base64 { * The actual number of significant bytes in your array is * given by numSigBytes. * - * @param source the array to convert - * @param srcOffset the index where conversion begins + * @param source the array to convert + * @param srcOffset the index where conversion begins * @param numSigBytes the number of significant bytes in your array * @param destination the array to hold the conversion - * @param destOffset the index where output will be put - * @param alphabet is the encoding alphabet + * @param destOffset the index where output will be put + * @param alphabet is the encoding alphabet * @return the destination array * @since 1.3 */ private static byte[] encode3to4(byte[] source, int srcOffset, - int numSigBytes, byte[] destination, int destOffset, byte[] alphabet) { + int numSigBytes, byte[] destination, int destOffset, byte[] alphabet) { // 1 2 3 // 01234567890123456789012345678901 Bit position // --------000000001111111122222222 Array position from threeBytes @@ -208,8 +220,8 @@ public class Base64 { // when Java treats a value as negative that is cast from a byte to an int. int inBuff = (numSigBytes > 0 ? ((source[srcOffset] << 24) >>> 8) : 0) - | (numSigBytes > 1 ? ((source[srcOffset + 1] << 24) >>> 16) : 0) - | (numSigBytes > 2 ? ((source[srcOffset + 2] << 24) >>> 24) : 0); + | (numSigBytes > 1 ? ((source[srcOffset + 1] << 24) >>> 16) : 0) + | (numSigBytes > 2 ? ((source[srcOffset + 2] << 24) >>> 24) : 0); switch (numSigBytes) { case 3: @@ -250,9 +262,9 @@ public class Base64 { /** * Encodes a byte array into web safe Base64 notation. * - * @param source The data to convert + * @param source The data to convert * @param doPadding is {@code true} to pad result with '=' chars - * if it does not fall on 3 byte boundaries + * if it does not fall on 3 byte boundaries */ public static String encodeWebSafe(byte[] source, boolean doPadding) { return encode(source, 0, source.length, WEBSAFE_ALPHABET, doPadding); @@ -261,22 +273,22 @@ public class Base64 { /** * Encodes a byte array into Base64 notation. * - * @param source the data to convert - * @param off offset in array where conversion should begin - * @param len length of data to convert - * @param alphabet the encoding alphabet + * @param source the data to convert + * @param off offset in array where conversion should begin + * @param len length of data to convert + * @param alphabet the encoding alphabet * @param doPadding is {@code true} to pad result with '=' chars - * if it does not fall on 3 byte boundaries + * if it does not fall on 3 byte boundaries * @since 1.4 */ public static String encode(byte[] source, int off, int len, byte[] alphabet, - boolean doPadding) { + boolean doPadding) { byte[] outBuff = encode(source, off, len, alphabet, Integer.MAX_VALUE); int outLen = outBuff.length; // If doPadding is false, set length to truncate '=' // padding characters - while (doPadding == false && outLen > 0) { + while (!doPadding && outLen > 0) { if (outBuff[outLen - 1] != '=') { break; } @@ -289,19 +301,19 @@ public class Base64 { /** * Encodes a byte array into Base64 notation. * - * @param source the data to convert - * @param off offset in array where conversion should begin - * @param len length of data to convert - * @param alphabet is the encoding alphabet + * @param source the data to convert + * @param off offset in array where conversion should begin + * @param len length of data to convert + * @param alphabet is the encoding alphabet * @param maxLineLength maximum length of one line. * @return the BASE64-encoded byte array */ public static byte[] encode(byte[] source, int off, int len, byte[] alphabet, - int maxLineLength) { + int maxLineLength) { int lenDiv3 = (len + 2) / 3; // ceil(len / 3) int len43 = lenDiv3 * 4; byte[] outBuff = new byte[len43 // Main 4:3 - + (len43 / maxLineLength)]; // New lines + + (len43 / maxLineLength)]; // New lines int d = 0; int e = 0; @@ -314,8 +326,8 @@ public class Base64 { // but inlined for faster encoding (~20% improvement) int inBuff = ((source[d + off] << 24) >>> 8) - | ((source[d + 1 + off] << 24) >>> 16) - | ((source[d + 2 + off] << 24) >>> 24); + | ((source[d + 1 + off] << 24) >>> 16) + | ((source[d + 2 + off] << 24) >>> 24); outBuff[e] = alphabet[(inBuff >>> 18)]; outBuff[e + 1] = alphabet[(inBuff >>> 12) & 0x3f]; outBuff[e + 2] = alphabet[(inBuff >>> 6) & 0x3f]; @@ -363,22 +375,21 @@ public class Base64 { * This method returns the actual number of bytes that * were converted from the Base64 encoding. * - * - * @param source the array to convert - * @param srcOffset the index where conversion begins + * @param source the array to convert + * @param srcOffset the index where conversion begins * @param destination the array to hold the conversion - * @param destOffset the index where output will be put - * @param decodabet the decodabet for decoding Base64 content + * @param destOffset the index where output will be put + * @param decodabet the decodabet for decoding Base64 content * @return the number of decoded bytes converted * @since 1.3 */ private static int decode4to3(byte[] source, int srcOffset, - byte[] destination, int destOffset, byte[] decodabet) { + byte[] destination, int destOffset, byte[] decodabet) { // Example: Dk== if (source[srcOffset + 2] == EQUALS_SIGN) { int outBuff = ((decodabet[source[srcOffset]] << 24) >>> 6) - | ((decodabet[source[srcOffset + 1]] << 24) >>> 12); + | ((decodabet[source[srcOffset + 1]] << 24) >>> 12); destination[destOffset] = (byte) (outBuff >>> 16); return 1; @@ -386,8 +397,8 @@ public class Base64 { // Example: DkL= int outBuff = ((decodabet[source[srcOffset]] << 24) >>> 6) - | ((decodabet[source[srcOffset + 1]] << 24) >>> 12) - | ((decodabet[source[srcOffset + 2]] << 24) >>> 18); + | ((decodabet[source[srcOffset + 1]] << 24) >>> 12) + | ((decodabet[source[srcOffset + 2]] << 24) >>> 18); destination[destOffset] = (byte) (outBuff >>> 16); destination[destOffset + 1] = (byte) (outBuff >>> 8); @@ -396,9 +407,9 @@ public class Base64 { // Example: DkLE int outBuff = ((decodabet[source[srcOffset]] << 24) >>> 6) - | ((decodabet[source[srcOffset + 1]] << 24) >>> 12) - | ((decodabet[source[srcOffset + 2]] << 24) >>> 18) - | ((decodabet[source[srcOffset + 3]] << 24) >>> 24); + | ((decodabet[source[srcOffset + 1]] << 24) >>> 12) + | ((decodabet[source[srcOffset + 2]] << 24) >>> 18) + | ((decodabet[source[srcOffset + 3]] << 24) >>> 24); destination[destOffset] = (byte) (outBuff >> 16); destination[destOffset + 1] = (byte) (outBuff >> 8); @@ -438,8 +449,8 @@ public class Base64 { * * @param source The Base64 encoded data * @return decoded data - * @since 1.3 * @throws Base64DecoderException + * @since 1.3 */ public static byte[] decode(byte[] source) throws Base64DecoderException { return decode(source, 0, source.length); @@ -466,8 +477,8 @@ public class Base64 { * @param off the offset of where to begin decoding * @param len the length of characters to decode * @return decoded data - * @since 1.3 * @throws Base64DecoderException + * @since 1.3 */ public static byte[] decode(byte[] source, int off, int len) throws Base64DecoderException { @@ -493,9 +504,9 @@ public class Base64 { * Decodes Base64 content using the supplied decodabet and returns * the decoded byte array. * - * @param source the Base64 encoded data - * @param off the offset of where to begin decoding - * @param len the length of characters to decode + * @param source the Base64 encoded data + * @param off the offset of where to begin decoding + * @param len the length of characters to decode * @param decodabet the decodabet for decoding Base64 content * @return decoded data */ diff --git a/app/llx/app/src/extreme/java/net/pierrox/lightning_launcher/iab/IabHelper.java b/app/llx/app/src/extreme/java/net/pierrox/lightning_launcher/iab/IabHelper.java index 7ced5c7..ffdb8e3 100644 --- a/app/llx/app/src/extreme/java/net/pierrox/lightning_launcher/iab/IabHelper.java +++ b/app/llx/app/src/extreme/java/net/pierrox/lightning_launcher/iab/IabHelper.java @@ -44,22 +44,22 @@ import java.util.List; * It provides synchronous (blocking) and asynchronous (non-blocking) methods for * many common in-app billing operations, as well as automatic signature * verification. - * + *

    * After instantiating, you must perform setup in order to start using the object. * To perform setup, call the {@link #startSetup} method and provide a listener; * that listener will be notified when setup is complete, after which (and not before) * you may call other methods. - * + *

    * After setup is complete, you will typically want to request an inventory of owned * items and subscriptions. See {@link #queryInventory}, {@link #queryInventoryAsync} * and related methods. - * + *

    * When you are done with this object, don't forget to call {@link #dispose} * to ensure proper cleanup. This object holds a binding to the in-app billing * service, which will leak unless you dispose of it correctly. If you created * the object on an Activity's onCreate method, then the recommended * place to dispose of it is the Activity's onDestroy method. - * + *

    * A note about threading: When using this object from a background thread, you may * call the blocking versions of methods; when using from a UI thread, call * only the asynchronous versions and handle the results via callbacks. @@ -68,47 +68,8 @@ import java.util.List; * has not yet completed will result in an exception being thrown. * * @author Bruno Oliveira (Google) - * */ public class IabHelper { - // Is debug logging enabled? - boolean mDebugLog = false; - String mDebugTag = "IabHelper"; - - // Is setup done? - boolean mSetupDone = false; - - // Has this object been disposed of? (If so, we should ignore callbacks, etc) - boolean mDisposed = false; - - // Are subscriptions supported? - boolean mSubscriptionsSupported = false; - - // Is an asynchronous operation in progress? - // (only one at a time can be in progress) - boolean mAsyncInProgress = false; - - // (for logging/debugging) - // if mAsyncInProgress == true, what asynchronous operation is in progress? - String mAsyncOperation = ""; - - // Context we were passed during initialization - Context mContext; - - // Connection to the service - IInAppBillingService mService; - ServiceConnection mServiceConn; - boolean mServiceBound; - - // The request code used to launch purchase flow - int mRequestCode; - - // The item type of the current purchase flow - String mPurchasingItemType; - - // Public key for verifying signature, in base64 encoding - String mSignatureBase64 = null; - // Billing response codes public static final int BILLING_RESPONSE_RESULT_OK = 0; public static final int BILLING_RESPONSE_RESULT_USER_CANCELED = 1; @@ -118,7 +79,6 @@ public class IabHelper { public static final int BILLING_RESPONSE_RESULT_ERROR = 6; public static final int BILLING_RESPONSE_RESULT_ITEM_ALREADY_OWNED = 7; public static final int BILLING_RESPONSE_RESULT_ITEM_NOT_OWNED = 8; - // IAB Helper error codes public static final int IABHELPER_ERROR_BASE = -1000; public static final int IABHELPER_REMOTE_EXCEPTION = -1001; @@ -131,7 +91,6 @@ public class IabHelper { public static final int IABHELPER_UNKNOWN_ERROR = -1008; public static final int IABHELPER_SUBSCRIPTIONS_NOT_AVAILABLE = -1009; public static final int IABHELPER_INVALID_CONSUMPTION = -1010; - // Keys for the responses from InAppBillingService public static final String RESPONSE_CODE = "RESPONSE_CODE"; public static final String RESPONSE_GET_SKU_DETAILS_LIST = "DETAILS_LIST"; @@ -142,25 +101,53 @@ public class IabHelper { public static final String RESPONSE_INAPP_PURCHASE_DATA_LIST = "INAPP_PURCHASE_DATA_LIST"; public static final String RESPONSE_INAPP_SIGNATURE_LIST = "INAPP_DATA_SIGNATURE_LIST"; public static final String INAPP_CONTINUATION_TOKEN = "INAPP_CONTINUATION_TOKEN"; - // Item types public static final String ITEM_TYPE_INAPP = "inapp"; public static final String ITEM_TYPE_SUBS = "subs"; - // some fields on the getSkuDetails response bundle public static final String GET_SKU_DETAILS_ITEM_LIST = "ITEM_ID_LIST"; public static final String GET_SKU_DETAILS_ITEM_TYPE_LIST = "ITEM_TYPE_LIST"; + // Is debug logging enabled? + boolean mDebugLog = false; + String mDebugTag = "IabHelper"; + // Is setup done? + boolean mSetupDone = false; + // Has this object been disposed of? (If so, we should ignore callbacks, etc) + boolean mDisposed = false; + // Are subscriptions supported? + boolean mSubscriptionsSupported = false; + // Is an asynchronous operation in progress? + // (only one at a time can be in progress) + boolean mAsyncInProgress = false; + // (for logging/debugging) + // if mAsyncInProgress == true, what asynchronous operation is in progress? + String mAsyncOperation = ""; + // Context we were passed during initialization + Context mContext; + // Connection to the service + IInAppBillingService mService; + ServiceConnection mServiceConn; + boolean mServiceBound; + // The request code used to launch purchase flow + int mRequestCode; + // The item type of the current purchase flow + String mPurchasingItemType; + // Public key for verifying signature, in base64 encoding + String mSignatureBase64 = null; + // The listener registered on launchPurchaseFlow, which we have to call back when + // the purchase finishes + OnIabPurchaseFinishedListener mPurchaseListener; /** * Creates an instance. After creation, it will not yet be ready to use. You must perform * setup by calling {@link #startSetup} and wait for setup to complete. This constructor does not * block and is safe to call from a UI thread. * - * @param ctx Your application or Activity context. Needed to bind to the in-app billing service. + * @param ctx Your application or Activity context. Needed to bind to the in-app billing service. * @param base64PublicKey Your application's public key, encoded in base64. - * This is used for verification of purchase signatures. You can find your app's base64-encoded - * public key in your application's page on Google Play Developer Console. Note that this - * is NOT your "developer public key". + * This is used for verification of purchase signatures. You can find your app's base64-encoded + * public key in your application's page on Google Play Developer Console. Note that this + * is NOT your "developer public key". */ public IabHelper(Context ctx, String base64PublicKey) { mContext = ctx.getApplicationContext(); @@ -168,6 +155,39 @@ public class IabHelper { logDebug("IAB helper created."); } + /** + * Returns a human-readable description for the given response code. + * + * @param code The response code + * @return A human-readable string explaining the result code. + * It also includes the result code numerically. + */ + public static String getResponseDesc(int code) { + String[] iab_msgs = ("0:OK/1:User Canceled/2:Unknown/" + + "3:Billing Unavailable/4:Item unavailable/" + + "5:Developer Error/6:Error/7:Item Already Owned/" + + "8:Item not owned").split("/"); + String[] iabhelper_msgs = ("0:OK/-1001:Remote exception during initialization/" + + "-1002:Bad response received/" + + "-1003:Purchase signature verification failed/" + + "-1004:Send intent failed/" + + "-1005:User cancelled/" + + "-1006:Unknown purchase response/" + + "-1007:Missing token/" + + "-1008:Unknown error/" + + "-1009:Subscriptions not available/" + + "-1010:Invalid consumption attempt").split("/"); + + if (code <= IABHELPER_ERROR_BASE) { + int index = IABHELPER_ERROR_BASE - code; + if (index >= 0 && index < iabhelper_msgs.length) return iabhelper_msgs[index]; + else return code + ":Unknown IAB Helper Error"; + } else if (code < 0 || code >= iab_msgs.length) + return code + ":Unknown"; + else + return iab_msgs[code]; + } + /** * Enables or disable debug logging through LogCat. */ @@ -182,19 +202,6 @@ public class IabHelper { mDebugLog = enable; } - /** - * Callback for setup process. This listener's {@link #onIabSetupFinished} method is called - * when the setup process is complete. - */ - public interface OnIabSetupFinishedListener { - /** - * Called to notify that setup is complete. - * - * @param result The result of the setup process. - */ - public void onIabSetupFinished(IabResult result); - } - /** * Starts the setup process. This will start up the setup process asynchronously. * You will be notified through the listener when the setup process is complete. @@ -225,9 +232,10 @@ public class IabHelper { try { logDebug("Checking for in-app billing 3 support."); - if(mService == null) { - if (listener != null) listener.onIabSetupFinished(new IabResult(BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE, - "Error checking for billing v3 support, no service.")); + if (mService == null) { + if (listener != null) + listener.onIabSetupFinished(new IabResult(BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE, + "Error checking for billing v3 support, no service.")); // if in-app purchases aren't supported, neither are subscriptions. mSubscriptionsSupported = false; @@ -251,17 +259,15 @@ public class IabHelper { if (response == BILLING_RESPONSE_RESULT_OK) { logDebug("Subscriptions AVAILABLE."); mSubscriptionsSupported = true; - } - else { + } else { logDebug("Subscriptions NOT AVAILABLE. Response: " + response); } mSetupDone = true; - } - catch (RemoteException e) { + } catch (RemoteException e) { if (listener != null) { listener.onIabSetupFinished(new IabResult(IABHELPER_REMOTE_EXCEPTION, - "RemoteException while setting up in-app billing.")); + "RemoteException while setting up in-app billing.")); } e.printStackTrace(); return; @@ -280,13 +286,12 @@ public class IabHelper { // service available to handle that Intent mContext.bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE); mServiceBound = true; - } - else { + } else { // no service available to handle that Intent if (listener != null) { listener.onIabSetupFinished( new IabResult(BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE, - "Billing service unavailable on device.")); + "Billing service unavailable on device.")); } } } @@ -319,52 +324,34 @@ public class IabHelper { } private void checkNotDisposed() { - if (mDisposed) throw new IllegalStateException("IabHelper was disposed of, so it cannot be used."); + if (mDisposed) + throw new IllegalStateException("IabHelper was disposed of, so it cannot be used."); } - /** Returns whether subscriptions are supported. */ + /** + * Returns whether subscriptions are supported. + */ public boolean subscriptionsSupported() { checkNotDisposed(); return mSubscriptionsSupported; } - - /** - * Callback that notifies when a purchase is finished. - */ - public interface OnIabPurchaseFinishedListener { - /** - * Called to notify that an in-app purchase finished. If the purchase was successful, - * then the sku parameter specifies which item was purchased. If the purchase failed, - * the sku and extraData parameters may or may not be null, depending on how far the purchase - * process went. - * - * @param result The result of the purchase. - * @param info The purchase information (null if purchase failed) - */ - public void onIabPurchaseFinished(IabResult result, Purchase info); - } - - // The listener registered on launchPurchaseFlow, which we have to call back when - // the purchase finishes - OnIabPurchaseFinishedListener mPurchaseListener; - public void launchPurchaseFlow(Activity act, String sku, int requestCode, OnIabPurchaseFinishedListener listener) { launchPurchaseFlow(act, sku, requestCode, listener, ""); } public void launchPurchaseFlow(Activity act, String sku, int requestCode, - OnIabPurchaseFinishedListener listener, String extraData) { + OnIabPurchaseFinishedListener listener, String extraData) { launchPurchaseFlow(act, sku, ITEM_TYPE_INAPP, requestCode, listener, extraData); } public void launchSubscriptionPurchaseFlow(Activity act, String sku, int requestCode, - OnIabPurchaseFinishedListener listener) { + OnIabPurchaseFinishedListener listener) { launchSubscriptionPurchaseFlow(act, sku, requestCode, listener, ""); } public void launchSubscriptionPurchaseFlow(Activity act, String sku, int requestCode, - OnIabPurchaseFinishedListener listener, String extraData) { + OnIabPurchaseFinishedListener listener, String extraData) { launchPurchaseFlow(act, sku, ITEM_TYPE_SUBS, requestCode, listener, extraData); } @@ -376,18 +363,18 @@ public class IabHelper { * this object's {@link #handleActivityResult} method to continue the purchase flow. This method * MUST be called from the UI thread of the Activity. * - * @param act The calling activity. - * @param sku The sku of the item to purchase. - * @param itemType indicates if it's a product or a subscription (ITEM_TYPE_INAPP or ITEM_TYPE_SUBS) + * @param act The calling activity. + * @param sku The sku of the item to purchase. + * @param itemType indicates if it's a product or a subscription (ITEM_TYPE_INAPP or ITEM_TYPE_SUBS) * @param requestCode A request code (to differentiate from other responses -- - * as in {@link Activity#startActivityForResult}). - * @param listener The listener to notify when the purchase process finishes - * @param extraData Extra data (developer payload), which will be returned with the purchase data - * when the purchase completes. This extra data will be permanently bound to that purchase - * and will always be returned when the purchase is queried. + * as in {@link Activity#startActivityForResult}). + * @param listener The listener to notify when the purchase process finishes + * @param extraData Extra data (developer payload), which will be returned with the purchase data + * when the purchase completes. This extra data will be permanently bound to that purchase + * and will always be returned when the purchase is queried. */ public void launchPurchaseFlow(Activity act, String sku, String itemType, int requestCode, - OnIabPurchaseFinishedListener listener, String extraData) { + OnIabPurchaseFinishedListener listener, String extraData) { checkNotDisposed(); checkSetupDone("launchPurchaseFlow"); flagStartAsync("launchPurchaseFlow"); @@ -419,19 +406,17 @@ public class IabHelper { mPurchaseListener = listener; mPurchasingItemType = itemType; act.startIntentSenderForResult(pendingIntent.getIntentSender(), - requestCode, new Intent(), - Integer.valueOf(0), Integer.valueOf(0), - Integer.valueOf(0)); - } - catch (SendIntentException e) { + requestCode, new Intent(), + Integer.valueOf(0), Integer.valueOf(0), + Integer.valueOf(0)); + } catch (SendIntentException e) { logError("SendIntentException while launching purchase flow for sku " + sku); e.printStackTrace(); flagEndAsync(); result = new IabResult(IABHELPER_SEND_INTENT_FAILED, "Failed to send intent."); if (listener != null) listener.onIabPurchaseFinished(result, null); - } - catch (RemoteException e) { + } catch (RemoteException e) { logError("RemoteException while launching purchase flow for sku " + sku); e.printStackTrace(); flagEndAsync(); @@ -448,11 +433,11 @@ public class IabHelper { * MUST be called from the UI thread of the Activity. * * @param requestCode The requestCode as you received it. - * @param resultCode The resultCode as you received it. - * @param data The data (Intent) as you received it. + * @param resultCode The resultCode as you received it. + * @param data The data (Intent) as you received it. * @return Returns true if the result was related to a purchase flow and was handled; - * false if the result was not related to a purchase, in which case you should - * handle it normally. + * false if the result was not related to a purchase, in which case you should + * handle it normally. */ public boolean handleActivityResult(int requestCode, int resultCode, Intent data) { IabResult result; @@ -486,7 +471,8 @@ public class IabHelper { logError("BUG: either purchaseData or dataSignature is null."); logDebug("Extras: " + data.getExtras().toString()); result = new IabResult(IABHELPER_UNKNOWN_ERROR, "IAB returned null purchaseData or dataSignature"); - if (mPurchaseListener != null) mPurchaseListener.onIabPurchaseFinished(result, null); + if (mPurchaseListener != null) + mPurchaseListener.onIabPurchaseFinished(result, null); return true; } @@ -499,38 +485,36 @@ public class IabHelper { if (!Security.verifyPurchase(mSignatureBase64, purchaseData, dataSignature)) { logError("Purchase signature verification FAILED for sku " + sku); result = new IabResult(IABHELPER_VERIFICATION_FAILED, "Signature verification failed for sku " + sku); - if (mPurchaseListener != null) mPurchaseListener.onIabPurchaseFinished(result, purchase); + if (mPurchaseListener != null) + mPurchaseListener.onIabPurchaseFinished(result, purchase); return true; } logDebug("Purchase signature successfully verified."); - } - catch (JSONException e) { + } catch (JSONException e) { logError("Failed to parse purchase data."); e.printStackTrace(); result = new IabResult(IABHELPER_BAD_RESPONSE, "Failed to parse purchase data."); - if (mPurchaseListener != null) mPurchaseListener.onIabPurchaseFinished(result, null); + if (mPurchaseListener != null) + mPurchaseListener.onIabPurchaseFinished(result, null); return true; } if (mPurchaseListener != null) { mPurchaseListener.onIabPurchaseFinished(new IabResult(BILLING_RESPONSE_RESULT_OK, "Success"), purchase); } - } - else if (resultCode == Activity.RESULT_OK) { + } else if (resultCode == Activity.RESULT_OK) { // result code was OK, but in-app billing response was not OK. logDebug("Result code was OK but in-app billing response was not OK: " + getResponseDesc(responseCode)); if (mPurchaseListener != null) { result = new IabResult(responseCode, "Problem purchashing item."); mPurchaseListener.onIabPurchaseFinished(result, null); } - } - else if (resultCode == Activity.RESULT_CANCELED) { + } else if (resultCode == Activity.RESULT_CANCELED) { logDebug("Purchase canceled - Response: " + getResponseDesc(responseCode)); result = new IabResult(IABHELPER_USER_CANCELLED, "User canceled."); if (mPurchaseListener != null) mPurchaseListener.onIabPurchaseFinished(result, null); - } - else { - logError("Purchase failed. Result code: " + Integer.toString(resultCode) + } else { + logError("Purchase failed. Result code: " + resultCode + ". Response: " + getResponseDesc(responseCode)); result = new IabResult(IABHELPER_UNKNOWN_PURCHASE_RESPONSE, "Unknown purchase response."); if (mPurchaseListener != null) mPurchaseListener.onIabPurchaseFinished(result, null); @@ -548,15 +532,15 @@ public class IabHelper { * Do not call from a UI thread. For that, use the non-blocking version {@link #refreshInventoryAsync}. * * @param querySkuDetails if true, SKU details (price, description, etc) will be queried as well - * as purchase information. - * @param moreItemSkus additional PRODUCT skus to query information on, regardless of ownership. - * Ignored if null or if querySkuDetails is false. - * @param moreSubsSkus additional SUBSCRIPTIONS skus to query information on, regardless of ownership. - * Ignored if null or if querySkuDetails is false. + * as purchase information. + * @param moreItemSkus additional PRODUCT skus to query information on, regardless of ownership. + * Ignored if null or if querySkuDetails is false. + * @param moreSubsSkus additional SUBSCRIPTIONS skus to query information on, regardless of ownership. + * Ignored if null or if querySkuDetails is false. * @throws IabException if a problem occurs while refreshing the inventory. */ public Inventory queryInventory(boolean querySkuDetails, List moreItemSkus, - List moreSubsSkus) throws IabException { + List moreSubsSkus) throws IabException { checkNotDisposed(); checkSetupDone("queryInventory"); try { @@ -589,29 +573,13 @@ public class IabHelper { } return inv; - } - catch (RemoteException e) { + } catch (RemoteException e) { throw new IabException(IABHELPER_REMOTE_EXCEPTION, "Remote exception while refreshing inventory.", e); - } - catch (JSONException e) { + } catch (JSONException e) { throw new IabException(IABHELPER_BAD_RESPONSE, "Error parsing JSON response while refreshing inventory.", e); } } - /** - * Listener that notifies when an inventory query operation completes. - */ - public interface QueryInventoryFinishedListener { - /** - * Called to notify that an inventory query operation completed. - * - * @param result The result of the operation. - * @param inv The inventory. - */ - public void onQueryInventoryFinished(IabResult result, Inventory inv); - } - - /** * Asynchronous wrapper for inventory query. This will perform an inventory * query as described in {@link #queryInventory}, but will do so asynchronously @@ -619,12 +587,12 @@ public class IabHelper { * call from a UI thread. * * @param querySkuDetails as in {@link #queryInventory} - * @param moreSkus as in {@link #queryInventory} - * @param listener The listener to notify when the refresh operation completes. + * @param moreSkus as in {@link #queryInventory} + * @param listener The listener to notify when the refresh operation completes. */ public void queryInventoryAsync(final boolean querySkuDetails, - final List moreSkus, - final QueryInventoryFinishedListener listener) { + final List moreSkus, + final QueryInventoryFinishedListener listener) { final Handler handler = new Handler(); checkNotDisposed(); checkSetupDone("queryInventory"); @@ -639,8 +607,7 @@ public class IabHelper { Inventory inv = null; try { inv = queryInventory(querySkuDetails, moreSkus); - } - catch (IabException ex) { + } catch (IabException ex) { result = ex.getResult(); } @@ -667,7 +634,6 @@ public class IabHelper { queryInventoryAsync(querySkuDetails, null, listener); } - /** * Consumes a given in-app product. Consuming can only be done on an item * that's owned, and as a result of consumption, the user will no longer own it. @@ -690,53 +656,24 @@ public class IabHelper { String token = itemInfo.getToken(); String sku = itemInfo.getSku(); if (token == null || token.equals("")) { - logError("Can't consume "+ sku + ". No token."); - throw new IabException(IABHELPER_MISSING_TOKEN, "PurchaseInfo is missing token for sku: " - + sku + " " + itemInfo); + logError("Can't consume " + sku + ". No token."); + throw new IabException(IABHELPER_MISSING_TOKEN, "PurchaseInfo is missing token for sku: " + + sku + " " + itemInfo); } logDebug("Consuming sku: " + sku + ", token: " + token); int response = mService.consumePurchase(3, mContext.getPackageName(), token); if (response == BILLING_RESPONSE_RESULT_OK) { - logDebug("Successfully consumed sku: " + sku); + logDebug("Successfully consumed sku: " + sku); + } else { + logDebug("Error consuming consuming sku " + sku + ". " + getResponseDesc(response)); + throw new IabException(response, "Error consuming sku " + sku); } - else { - logDebug("Error consuming consuming sku " + sku + ". " + getResponseDesc(response)); - throw new IabException(response, "Error consuming sku " + sku); - } - } - catch (RemoteException e) { + } catch (RemoteException e) { throw new IabException(IABHELPER_REMOTE_EXCEPTION, "Remote exception while consuming. PurchaseInfo: " + itemInfo, e); } } - /** - * Callback that notifies when a consumption operation finishes. - */ - public interface OnConsumeFinishedListener { - /** - * Called to notify that a consumption has finished. - * - * @param purchase The purchase that was (or was to be) consumed. - * @param result The result of the consumption operation. - */ - public void onConsumeFinished(Purchase purchase, IabResult result); - } - - /** - * Callback that notifies when a multi-item consumption operation finishes. - */ - public interface OnConsumeMultiFinishedListener { - /** - * Called to notify that a consumption of multiple items has finished. - * - * @param purchases The purchases that were (or were to be) consumed. - * @param results The results of each consumption operation, corresponding to each - * sku. - */ - public void onConsumeMultiFinished(List purchases, List results); - } - /** * Asynchronous wrapper to item consumption. Works like {@link #consume}, but * performs the consumption in the background and notifies completion through @@ -755,8 +692,9 @@ public class IabHelper { /** * Same as {@link consumeAsync}, but for multiple items at once. + * * @param purchases The list of PurchaseInfo objects representing the purchases to consume. - * @param listener The listener to notify when the consumption operation finishes. + * @param listener The listener to notify when the consumption operation finishes. */ public void consumeAsync(List purchases, OnConsumeMultiFinishedListener listener) { checkNotDisposed(); @@ -764,41 +702,6 @@ public class IabHelper { consumeAsyncInternal(purchases, null, listener); } - /** - * Returns a human-readable description for the given response code. - * - * @param code The response code - * @return A human-readable string explaining the result code. - * It also includes the result code numerically. - */ - public static String getResponseDesc(int code) { - String[] iab_msgs = ("0:OK/1:User Canceled/2:Unknown/" + - "3:Billing Unavailable/4:Item unavailable/" + - "5:Developer Error/6:Error/7:Item Already Owned/" + - "8:Item not owned").split("/"); - String[] iabhelper_msgs = ("0:OK/-1001:Remote exception during initialization/" + - "-1002:Bad response received/" + - "-1003:Purchase signature verification failed/" + - "-1004:Send intent failed/" + - "-1005:User cancelled/" + - "-1006:Unknown purchase response/" + - "-1007:Missing token/" + - "-1008:Unknown error/" + - "-1009:Subscriptions not available/" + - "-1010:Invalid consumption attempt").split("/"); - - if (code <= IABHELPER_ERROR_BASE) { - int index = IABHELPER_ERROR_BASE - code; - if (index >= 0 && index < iabhelper_msgs.length) return iabhelper_msgs[index]; - else return String.valueOf(code) + ":Unknown IAB Helper Error"; - } - else if (code < 0 || code >= iab_msgs.length) - return String.valueOf(code) + ":Unknown"; - else - return iab_msgs[code]; - } - - // Checks that setup was done; if not, throws an exception. void checkSetupDone(String operation) { if (!mSetupDone) { @@ -813,9 +716,8 @@ public class IabHelper { if (o == null) { logDebug("Bundle with null response code, assuming OK (known issue)"); return BILLING_RESPONSE_RESULT_OK; - } - else if (o instanceof Integer) return ((Integer)o).intValue(); - else if (o instanceof Long) return (int)((Long)o).longValue(); + } else if (o instanceof Integer) return ((Integer) o).intValue(); + else if (o instanceof Long) return (int) ((Long) o).longValue(); else { logError("Unexpected type for bundle response code."); logError(o.getClass().getName()); @@ -829,9 +731,8 @@ public class IabHelper { if (o == null) { logError("Intent with no response code, assuming OK (known issue)"); return BILLING_RESPONSE_RESULT_OK; - } - else if (o instanceof Integer) return ((Integer)o).intValue(); - else if (o instanceof Long) return (int)((Long)o).longValue(); + } else if (o instanceof Integer) return ((Integer) o).intValue(); + else if (o instanceof Long) return (int) ((Long) o).longValue(); else { logError("Unexpected type for intent response code."); logError(o.getClass().getName()); @@ -853,7 +754,6 @@ public class IabHelper { mAsyncInProgress = false; } - int queryPurchases(Inventory inv, String itemType) throws JSONException, RemoteException { // Query purchases logDebug("Querying owned items, item type: " + itemType); @@ -867,7 +767,7 @@ public class IabHelper { itemType, continueToken); int response = getResponseCodeFromBundle(ownedItems); - logDebug("Owned items response: " + String.valueOf(response)); + logDebug("Owned items response: " + response); if (response != BILLING_RESPONSE_RESULT_OK) { logDebug("getPurchases() failed: " + getResponseDesc(response)); return response; @@ -880,11 +780,11 @@ public class IabHelper { } ArrayList ownedSkus = ownedItems.getStringArrayList( - RESPONSE_INAPP_ITEM_LIST); + RESPONSE_INAPP_ITEM_LIST); ArrayList purchaseDataList = ownedItems.getStringArrayList( - RESPONSE_INAPP_PURCHASE_DATA_LIST); + RESPONSE_INAPP_PURCHASE_DATA_LIST); ArrayList signatureList = ownedItems.getStringArrayList( - RESPONSE_INAPP_SIGNATURE_LIST); + RESPONSE_INAPP_SIGNATURE_LIST); for (int i = 0; i < purchaseDataList.size(); ++i) { String purchaseData = purchaseDataList.get(i); @@ -901,8 +801,7 @@ public class IabHelper { // Record ownership and token inv.addPurchase(purchase); - } - else { + } else { logWarn("Purchase signature verification **FAILED**. Not adding item."); logDebug(" Purchase data: " + purchaseData); logDebug(" Signature: " + signature); @@ -918,7 +817,7 @@ public class IabHelper { } int querySkuDetails(String itemType, Inventory inv, List moreSkus) - throws RemoteException, JSONException { + throws RemoteException, JSONException { logDebug("Querying SKU details."); ArrayList skuList = new ArrayList(); skuList.addAll(inv.getAllOwnedSkus(itemType)); @@ -945,8 +844,7 @@ public class IabHelper { if (response != BILLING_RESPONSE_RESULT_OK) { logDebug("getSkuDetails() failed: " + getResponseDesc(response)); return response; - } - else { + } else { logError("getSkuDetails() returned a bundle with neither an error nor a detail list."); return IABHELPER_BAD_RESPONSE; } @@ -963,7 +861,6 @@ public class IabHelper { return BILLING_RESPONSE_RESULT_OK; } - void consumeAsyncInternal(final List purchases, final OnConsumeFinishedListener singleListener, final OnConsumeMultiFinishedListener multiListener) { @@ -976,8 +873,7 @@ public class IabHelper { try { consume(purchase); results.add(new IabResult(BILLING_RESPONSE_RESULT_OK, "Successful consume of sku " + purchase.getSku())); - } - catch (IabException ex) { + } catch (IabException ex) { results.add(ex.getResult()); } } @@ -1012,4 +908,74 @@ public class IabHelper { void logWarn(String msg) { Log.w(mDebugTag, "In-app billing warning: " + msg); } + + /** + * Callback for setup process. This listener's {@link #onIabSetupFinished} method is called + * when the setup process is complete. + */ + public interface OnIabSetupFinishedListener { + /** + * Called to notify that setup is complete. + * + * @param result The result of the setup process. + */ + void onIabSetupFinished(IabResult result); + } + + + /** + * Callback that notifies when a purchase is finished. + */ + public interface OnIabPurchaseFinishedListener { + /** + * Called to notify that an in-app purchase finished. If the purchase was successful, + * then the sku parameter specifies which item was purchased. If the purchase failed, + * the sku and extraData parameters may or may not be null, depending on how far the purchase + * process went. + * + * @param result The result of the purchase. + * @param info The purchase information (null if purchase failed) + */ + void onIabPurchaseFinished(IabResult result, Purchase info); + } + + /** + * Listener that notifies when an inventory query operation completes. + */ + public interface QueryInventoryFinishedListener { + /** + * Called to notify that an inventory query operation completed. + * + * @param result The result of the operation. + * @param inv The inventory. + */ + void onQueryInventoryFinished(IabResult result, Inventory inv); + } + + /** + * Callback that notifies when a consumption operation finishes. + */ + public interface OnConsumeFinishedListener { + /** + * Called to notify that a consumption has finished. + * + * @param purchase The purchase that was (or was to be) consumed. + * @param result The result of the consumption operation. + */ + void onConsumeFinished(Purchase purchase, IabResult result); + } + + /** + * Callback that notifies when a multi-item consumption operation finishes. + */ + public interface OnConsumeMultiFinishedListener { + /** + * Called to notify that a consumption of multiple items has finished. + * + * @param purchases The purchases that were (or were to be) consumed. + * @param results The results of each consumption operation, corresponding to each + * sku. + */ + void onConsumeMultiFinished(List purchases, List results); + } } diff --git a/app/llx/app/src/extreme/java/net/pierrox/lightning_launcher/iab/Inventory.java b/app/llx/app/src/extreme/java/net/pierrox/lightning_launcher/iab/Inventory.java index ae0f0b4..de3ee77 100644 --- a/app/llx/app/src/extreme/java/net/pierrox/lightning_launcher/iab/Inventory.java +++ b/app/llx/app/src/extreme/java/net/pierrox/lightning_launcher/iab/Inventory.java @@ -25,27 +25,36 @@ import java.util.Map; * An Inventory is returned by such methods as {@link IabHelper#queryInventory}. */ public class Inventory { - Map mSkuMap = new HashMap(); - Map mPurchaseMap = new HashMap(); + Map mSkuMap = new HashMap(); + Map mPurchaseMap = new HashMap(); - Inventory() { } + Inventory() { + } - /** Returns the listing details for an in-app product. */ + /** + * Returns the listing details for an in-app product. + */ public SkuDetails getSkuDetails(String sku) { return mSkuMap.get(sku); } - /** Returns purchase information for a given product, or null if there is no purchase. */ + /** + * Returns purchase information for a given product, or null if there is no purchase. + */ public Purchase getPurchase(String sku) { return mPurchaseMap.get(sku); } - /** Returns whether or not there exists a purchase of the given product. */ + /** + * Returns whether or not there exists a purchase of the given product. + */ public boolean hasPurchase(String sku) { return mPurchaseMap.containsKey(sku); } - /** Return whether or not details about the given product are available. */ + /** + * Return whether or not details about the given product are available. + */ public boolean hasDetails(String sku) { return mSkuMap.containsKey(sku); } @@ -59,15 +68,19 @@ public class Inventory { * a new Inventory. */ public void erasePurchase(String sku) { - if (mPurchaseMap.containsKey(sku)) mPurchaseMap.remove(sku); + mPurchaseMap.remove(sku); } - /** Returns a list of all owned product IDs. */ + /** + * Returns a list of all owned product IDs. + */ List getAllOwnedSkus() { return new ArrayList(mPurchaseMap.keySet()); } - /** Returns a list of all owned product IDs of a given type */ + /** + * Returns a list of all owned product IDs of a given type + */ List getAllOwnedSkus(String itemType) { List result = new ArrayList(); for (Purchase p : mPurchaseMap.values()) { @@ -76,7 +89,9 @@ public class Inventory { return result; } - /** Returns a list of all purchases. */ + /** + * Returns a list of all purchases. + */ List getAllPurchases() { return new ArrayList(mPurchaseMap.values()); } diff --git a/app/llx/app/src/main/java/com/boombuler/system/appwidgetpicker/AppWidgetPickerActivity.java b/app/llx/app/src/main/java/com/boombuler/system/appwidgetpicker/AppWidgetPickerActivity.java index 0b7c3d7..d36499e 100644 --- a/app/llx/app/src/main/java/com/boombuler/system/appwidgetpicker/AppWidgetPickerActivity.java +++ b/app/llx/app/src/main/java/com/boombuler/system/appwidgetpicker/AppWidgetPickerActivity.java @@ -16,13 +16,7 @@ package com.boombuler.system.appwidgetpicker; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - import android.annotation.TargetApi; -import android.app.Activity; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProviderInfo; import android.content.ComponentName; @@ -37,56 +31,61 @@ import android.view.Window; import net.pierrox.lightning_launcher.LLApp; import net.pierrox.lightning_launcher.activities.ResourceWrapperActivity; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + public class AppWidgetPickerActivity extends ResourceWrapperActivity { private static final int REQUEST_BIND_APPWIDGET = 1; - private Intent fIntent = null; - private PackageManager fPManager = null; - private AppWidgetManager fAppWManager = null; - private ArrayList fItems; - private int fAppWidgetId; + private Intent fIntent = null; + private PackageManager fPManager = null; + private AppWidgetManager fAppWManager = null; + private ArrayList fItems; + private int fAppWidgetId; - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - this.setTitle(""); - requestWindowFeature(Window.FEATURE_NO_TITLE); + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + this.setTitle(""); + requestWindowFeature(Window.FEATURE_NO_TITLE); - fIntent = getIntent(); + fIntent = getIntent(); - final Intent intent = getIntent(); + final Intent intent = getIntent(); if (intent.hasExtra(AppWidgetManager.EXTRA_APPWIDGET_ID)) { fAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); fPManager = getPackageManager(); - fAppWManager = AppWidgetManager.getInstance(this); + fAppWManager = AppWidgetManager.getInstance(this); - fItems = new ArrayList(); - AddAppWidgetProviderInfos(); - AddCustomAppWidgets(); - Collections.sort(fItems, new Comparator() { + fItems = new ArrayList(); + AddAppWidgetProviderInfos(); + AddCustomAppWidgets(); + Collections.sort(fItems, new Comparator() { - @Override - public int compare(SubItem object1, SubItem object2) { - return object1.getName().compareToIgnoreCase(object2.getName()); - } + @Override + public int compare(SubItem object1, SubItem object2) { + return object1.getName().compareToIgnoreCase(object2.getName()); + } - }); - for(SubItem itm : fItems) { - if (itm instanceof Item) { - ((Item)itm).sort(); - } - } - new PickWidgetDialog(this).showDialog(null); + }); + for (SubItem itm : fItems) { + if (itm instanceof Item) { + ((Item) itm).sort(); + } + } + new PickWidgetDialog(this).showDialog(null); } else { finish(); } - } + } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { - if(requestCode == REQUEST_BIND_APPWIDGET) { - if(resultCode == RESULT_OK) { + if (requestCode == REQUEST_BIND_APPWIDGET) { + if (resultCode == RESULT_OK) { setResult(RESULT_OK); } else { LLApp.get().getAppWidgetHost().deleteAppWidgetId(fAppWidgetId); @@ -98,11 +97,11 @@ public class AppWidgetPickerActivity extends ResourceWrapperActivity { } public ArrayList getItems() { - return fItems; - } + return fItems; + } - @TargetApi(Build.VERSION_CODES.JELLY_BEAN) + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) public void finishOk(SubItem item) { int result; if (item.getExtra() != null) { @@ -111,7 +110,7 @@ public class AppWidgetPickerActivity extends ResourceWrapperActivity { setResult(RESULT_OK, getIntent(item)); } else { try { - if(fAppWManager.bindAppWidgetIdIfAllowed(fAppWidgetId, item.getProvider())) { + if (fAppWManager.bindAppWidgetIdIfAllowed(fAppWidgetId, item.getProvider())) { result = RESULT_OK; } else { Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_BIND); @@ -131,15 +130,15 @@ public class AppWidgetPickerActivity extends ResourceWrapperActivity { setResult(result, fIntent); } finish(); - } + } - /** + /** * Build the {@link Intent} described by this item. If this item * can't create a valid {@link ComponentName}, it will return * {@link Intent#ACTION_CREATE_SHORTCUT} filled with the item label. */ private Intent getIntent(SubItem itm) { - Intent intent = null; + Intent intent = null; Parcelable parcel = fIntent.getParcelableExtra(Intent.EXTRA_INTENT); if (parcel instanceof Intent) { intent = new Intent((Intent) parcel); @@ -162,47 +161,43 @@ public class AppWidgetPickerActivity extends ResourceWrapperActivity { return intent; } - private Item getPackageItem(AppWidgetProviderInfo info) { - String packName = info.provider.getPackageName(); - for (SubItem itm : fItems) { - if (itm instanceof Item) { - Item i = (Item)itm; - if (i.getPackageName().equals(packName)) { - return i; - } - } - } - try - { - android.content.pm.ApplicationInfo appInfo = fPManager.getApplicationInfo(info.provider.getPackageName(), 0); - Drawable appIcon = fPManager.getApplicationIcon(appInfo); - CharSequence str = fPManager.getApplicationLabel(appInfo); - Item newItm = new Item(str.toString(), appIcon); - newItm.setPackageName(packName); - fItems.add(newItm); - return newItm; - } - catch(PackageManager.NameNotFoundException expt) { - } - return null; - } + private Item getPackageItem(AppWidgetProviderInfo info) { + String packName = info.provider.getPackageName(); + for (SubItem itm : fItems) { + if (itm instanceof Item) { + Item i = (Item) itm; + if (i.getPackageName().equals(packName)) { + return i; + } + } + } + try { + android.content.pm.ApplicationInfo appInfo = fPManager.getApplicationInfo(info.provider.getPackageName(), 0); + Drawable appIcon = fPManager.getApplicationIcon(appInfo); + CharSequence str = fPManager.getApplicationLabel(appInfo); + Item newItm = new Item(str.toString(), appIcon); + newItm.setPackageName(packName); + fItems.add(newItm); + return newItm; + } catch (PackageManager.NameNotFoundException expt) { + } + return null; + } - private void AddAppWidgetProviderInfos() { - List infos = fAppWManager.getInstalledProviders(); + private void AddAppWidgetProviderInfos() { + List infos = fAppWManager.getInstalledProviders(); - for(AppWidgetProviderInfo info : infos) { - try - { - android.content.pm.ApplicationInfo appInfo = fPManager.getApplicationInfo(info.provider.getPackageName(), 0); - SubItem itm = new SubItem(info.label, fPManager.getDrawable(info.provider.getPackageName(), info.icon, appInfo)); - itm.setProvider(info.provider); - Item mainItm = getPackageItem(info); - mainItm.getItems().add(itm); - } - catch(PackageManager.NameNotFoundException expt) { - } - } - } + for (AppWidgetProviderInfo info : infos) { + try { + android.content.pm.ApplicationInfo appInfo = fPManager.getApplicationInfo(info.provider.getPackageName(), 0); + SubItem itm = new SubItem(info.label, fPManager.getDrawable(info.provider.getPackageName(), info.icon, appInfo)); + itm.setProvider(info.provider); + Item mainItm = getPackageItem(info); + mainItm.getItems().add(itm); + } catch (PackageManager.NameNotFoundException expt) { + } + } + } private void AddCustomAppWidgets() { final Bundle extras = fIntent.getExtras(); @@ -210,7 +205,8 @@ public class AppWidgetPickerActivity extends ResourceWrapperActivity { // get and validate the extras they gave us ArrayList customInfo = null; ArrayList customExtras = null; - try_custom_items: { + try_custom_items: + { customInfo = extras.getParcelableArrayList(AppWidgetManager.EXTRA_CUSTOM_INFO); if (customInfo == null || customInfo.size() == 0) { @@ -218,7 +214,7 @@ public class AppWidgetPickerActivity extends ResourceWrapperActivity { } int customInfoSize = customInfo.size(); - for (int i=0; i appWidgets, List customExtras) { - if (appWidgets == null) - return; + if (appWidgets == null) + return; final int size = appWidgets.size(); for (int i = 0; i < size; i++) { AppWidgetProviderInfo info = appWidgets.get(i); - String label = info.label.toString(); + String label = info.label; Drawable icon = null; if (info.icon != 0) { @@ -267,7 +263,7 @@ public class AppWidgetPickerActivity extends ResourceWrapperActivity { item.setPackageName(info.provider.getPackageName()); if (customExtras != null) { - subItem.setExtra(customExtras.get(i)); + subItem.setExtra(customExtras.get(i)); } fItems.add(item); diff --git a/app/llx/app/src/main/java/com/boombuler/system/appwidgetpicker/ItemAdapter.java b/app/llx/app/src/main/java/com/boombuler/system/appwidgetpicker/ItemAdapter.java index 5c33526..742c209 100644 --- a/app/llx/app/src/main/java/com/boombuler/system/appwidgetpicker/ItemAdapter.java +++ b/app/llx/app/src/main/java/com/boombuler/system/appwidgetpicker/ItemAdapter.java @@ -15,8 +15,6 @@ */ package com.boombuler.system.appwidgetpicker; -import java.util.ArrayList; - import android.content.Context; import android.view.LayoutInflater; import android.view.View; @@ -27,49 +25,48 @@ import android.widget.TextView; import net.pierrox.lightning_launcher_extreme.R; +import java.util.ArrayList; + public class ItemAdapter extends ArrayAdapter { - private final ArrayList items; - private final Context fContext; + private final ArrayList items; + private final Context fContext; - public ItemAdapter(Context context, int textViewResourceId, ArrayList items) { + public ItemAdapter(Context context, int textViewResourceId, ArrayList items) { super(context, textViewResourceId, items); this.items = items; fContext = context; - } + } - @Override - public View getView(int position, View convertView, ViewGroup parent) { + @Override + public View getView(int position, View convertView, ViewGroup parent) { View v = convertView; if (v == null) { - LayoutInflater vi = (LayoutInflater)fContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + LayoutInflater vi = (LayoutInflater) fContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); v = vi.inflate(R.layout.appwidgetpicker, null); } SubItem o = items.get(position); v.setTag(o); if (o != null) { - TextView tv = (TextView) v.findViewById(R.id.appwidgetpicker_textview); - TextView count_view = (TextView) v.findViewById(R.id.appwidgetpicker_count); - ImageView iv = (ImageView) v.findViewById(R.id.appwidgetpicker_imageview); + TextView tv = v.findViewById(R.id.appwidgetpicker_textview); + TextView count_view = v.findViewById(R.id.appwidgetpicker_count); + ImageView iv = v.findViewById(R.id.appwidgetpicker_imageview); if (tv != null) { - tv.setText(o.getName()); + tv.setText(o.getName()); } if (count_view != null) { - if (o instanceof Item) - { - int cnt = ((Item)o).getItems().size(); - if (cnt > 1) { - count_view.setText(String.format(fContext.getString(R.string.widget_count), cnt)); - count_view.setVisibility(View.VISIBLE); - } - else - count_view.setVisibility(View.GONE); - } - else - count_view.setVisibility(View.GONE); + if (o instanceof Item) { + int cnt = ((Item) o).getItems().size(); + if (cnt > 1) { + count_view.setText(String.format(fContext.getString(R.string.widget_count), cnt)); + count_view.setVisibility(View.VISIBLE); + } else + count_view.setVisibility(View.GONE); + } else + count_view.setVisibility(View.GONE); } - if(iv != null){ - iv.setImageDrawable(o.getImage()); + if (iv != null) { + iv.setImageDrawable(o.getImage()); } } return v; diff --git a/app/llx/app/src/main/java/com/boombuler/system/appwidgetpicker/SubItem.java b/app/llx/app/src/main/java/com/boombuler/system/appwidgetpicker/SubItem.java index c174c4e..0ca450a 100644 --- a/app/llx/app/src/main/java/com/boombuler/system/appwidgetpicker/SubItem.java +++ b/app/llx/app/src/main/java/com/boombuler/system/appwidgetpicker/SubItem.java @@ -20,35 +20,38 @@ import android.content.ComponentName; import android.graphics.drawable.Drawable; import android.os.Bundle; -public class SubItem { - private String fName; - private Drawable fImage; - public Bundle fExtra = null; - public ComponentName fProvider = null; - - public SubItem(String name, Drawable image) { - fName = name; - fImage = image; - } - - public void setExtra(Bundle aValue) { - fExtra = aValue; - } - public Bundle getExtra() { - return fExtra; - } - - public void setProvider(ComponentName aValue) { - fProvider = aValue; - } - public ComponentName getProvider() { - return fProvider; - } - - public String getName() { - return fName; - } - public Drawable getImage() { - return fImage; - } +public class SubItem { + private final String fName; + private final Drawable fImage; + public Bundle fExtra = null; + public ComponentName fProvider = null; + + public SubItem(String name, Drawable image) { + fName = name; + fImage = image; + } + + public Bundle getExtra() { + return fExtra; + } + + public void setExtra(Bundle aValue) { + fExtra = aValue; + } + + public ComponentName getProvider() { + return fProvider; + } + + public void setProvider(ComponentName aValue) { + fProvider = aValue; + } + + public String getName() { + return fName; + } + + public Drawable getImage() { + return fImage; + } } diff --git a/app/llx/app/src/main/java/com/google/android/hotword/client/HotwordServiceClient.java b/app/llx/app/src/main/java/com/google/android/hotword/client/HotwordServiceClient.java index a8761b2..8379de1 100644 --- a/app/llx/app/src/main/java/com/google/android/hotword/client/HotwordServiceClient.java +++ b/app/llx/app/src/main/java/com/google/android/hotword/client/HotwordServiceClient.java @@ -18,116 +18,117 @@ import com.google.android.hotword.service.IHotwordService; @TargetApi(Build.VERSION_CODES.KITKAT) public class HotwordServiceClient { - @SuppressWarnings("unused") - private static final boolean DBG = false; - private static final String HOTWORD_SERVICE = "com.google.android.googlequicksearchbox.HOTWORD_SERVICE"; - private static final String TAG = "HotwordServiceClient"; - private static final String VEL_PACKAGE = "com.google.android.googlequicksearchbox"; + @SuppressWarnings("unused") + private static final boolean DBG = false; + private static final String HOTWORD_SERVICE = "com.google.android.googlequicksearchbox.HOTWORD_SERVICE"; + private static final String TAG = "HotwordServiceClient"; + private static final String VEL_PACKAGE = "com.google.android.googlequicksearchbox"; - private final Activity mActivity; - private final ServiceConnection mConnection; - private final WindowId.FocusObserver mFocusObserver; + private final Activity mActivity; + private final ServiceConnection mConnection; + private final WindowId.FocusObserver mFocusObserver; - private IHotwordService mHotwordService; + private IHotwordService mHotwordService; - private boolean mHotwordStart; - private boolean mIsAvailable = true; - private boolean mIsBound; - private boolean mIsFocused = false; - private boolean mIsRequested = true; + private boolean mHotwordStart; + private boolean mIsAvailable = true; + private boolean mIsBound; + private boolean mIsFocused = false; + private boolean mIsRequested = true; - public HotwordServiceClient(Activity activity) { - mActivity = activity; - mConnection = new HotwordServiceConnection(); - mFocusObserver = new WindowFocusObserver(); - } + public HotwordServiceClient(Activity activity) { + mActivity = activity; + mConnection = new HotwordServiceConnection(); + mFocusObserver = new WindowFocusObserver(); + } - private void assertMainThread() { - if (Looper.getMainLooper().getThread() != Thread.currentThread()) - throw new IllegalStateException("Must be called on the main thread."); - } + private void assertMainThread() { + if (Looper.getMainLooper().getThread() != Thread.currentThread()) + throw new IllegalStateException("Must be called on the main thread."); + } - private void internalBind() { - if (!mIsAvailable || mIsBound) { - if (!mIsAvailable) - Log.w(TAG, "Hotword service is not available."); - return; - } + private void internalBind() { + if (!mIsAvailable || mIsBound) { + if (!mIsAvailable) + Log.w(TAG, "Hotword service is not available."); + return; + } - Intent localIntent = new Intent(HOTWORD_SERVICE).setPackage(VEL_PACKAGE); - mIsAvailable = mActivity.bindService(localIntent, mConnection, Context.BIND_AUTO_CREATE); - mIsBound = mIsAvailable; - } + Intent localIntent = new Intent(HOTWORD_SERVICE).setPackage(VEL_PACKAGE); + mIsAvailable = mActivity.bindService(localIntent, mConnection, Context.BIND_AUTO_CREATE); + mIsBound = mIsAvailable; + } - private void internalRequestHotword() { - if (mIsFocused && mIsRequested) { - if (!mHotwordStart) { - mHotwordStart = true; - if (!mIsBound) { - internalBind(); - } - } - } + private void internalRequestHotword() { + if (mIsFocused && mIsRequested) { + if (!mHotwordStart) { + mHotwordStart = true; + if (!mIsBound) { + internalBind(); + } + } + } - try { - if (mHotwordService != null) - mHotwordService.requestHotwordDetection(mActivity.getPackageName(), mIsFocused && mIsRequested); - } catch (RemoteException e) { - Log.w(TAG, "requestHotwordDetection - remote call failed", e); - return; - } - } + try { + if (mHotwordService != null) + mHotwordService.requestHotwordDetection(mActivity.getPackageName(), mIsFocused && mIsRequested); + } catch (RemoteException e) { + Log.w(TAG, "requestHotwordDetection - remote call failed", e); + } + } - public final void onAttachedToWindow() { - assertMainThread(); - mActivity.getWindow().getDecorView().getWindowId().registerFocusObserver(mFocusObserver); - internalBind(); - } + public final void onAttachedToWindow() { + assertMainThread(); + mActivity.getWindow().getDecorView().getWindowId().registerFocusObserver(mFocusObserver); + internalBind(); + } - @SuppressLint("MissingSuperCall") - public final void onDetachedFromWindow() { - if (!mIsBound) { - return; - } + @SuppressLint("MissingSuperCall") + public final void onDetachedFromWindow() { + if (!mIsBound) { + return; + } - assertMainThread(); - mActivity.getWindow().getDecorView().getWindowId().unregisterFocusObserver(mFocusObserver); - mActivity.unbindService(mConnection); - mIsBound = false; - } + assertMainThread(); + mActivity.getWindow().getDecorView().getWindowId().unregisterFocusObserver(mFocusObserver); + mActivity.unbindService(mConnection); + mIsBound = false; + } - public final void requestHotwordDetection(boolean detect) { - assertMainThread(); - mIsRequested = detect; - internalRequestHotword(); - } + public final void requestHotwordDetection(boolean detect) { + assertMainThread(); + mIsRequested = detect; + internalRequestHotword(); + } - private class HotwordServiceConnection implements ServiceConnection { - private HotwordServiceConnection() {} + private class HotwordServiceConnection implements ServiceConnection { + private HotwordServiceConnection() { + } - public void onServiceConnected(ComponentName componentName, IBinder iBinder) { - mHotwordService = IHotwordService.Stub.asInterface(iBinder); - internalRequestHotword(); - } + public void onServiceConnected(ComponentName componentName, IBinder iBinder) { + mHotwordService = IHotwordService.Stub.asInterface(iBinder); + internalRequestHotword(); + } - public void onServiceDisconnected(ComponentName componentName) { - mIsBound = false; - mHotwordService = null; - } - } + public void onServiceDisconnected(ComponentName componentName) { + mIsBound = false; + mHotwordService = null; + } + } - private class WindowFocusObserver extends WindowId.FocusObserver { - private WindowFocusObserver() {} + private class WindowFocusObserver extends WindowId.FocusObserver { + private WindowFocusObserver() { + } - public void onFocusGained(WindowId wid) { - mIsFocused = true; - internalRequestHotword(); - } + public void onFocusGained(WindowId wid) { + mIsFocused = true; + internalRequestHotword(); + } - public void onFocusLost(WindowId wid) { - mIsFocused = false; - internalRequestHotword(); - } - } + public void onFocusLost(WindowId wid) { + mIsFocused = false; + internalRequestHotword(); + } + } } diff --git a/app/llx/app/src/main/java/com/google/android/hotword/service/IHotwordService.java b/app/llx/app/src/main/java/com/google/android/hotword/service/IHotwordService.java index fc53964..a877a65 100644 --- a/app/llx/app/src/main/java/com/google/android/hotword/service/IHotwordService.java +++ b/app/llx/app/src/main/java/com/google/android/hotword/service/IHotwordService.java @@ -6,72 +6,72 @@ import android.os.IInterface; import android.os.Parcel; import android.os.RemoteException; -public abstract interface IHotwordService extends IInterface { - public abstract void requestHotwordDetection(String packageName, boolean detect) throws RemoteException; +public interface IHotwordService extends IInterface { + void requestHotwordDetection(String packageName, boolean detect) throws RemoteException; - public static abstract class Stub extends Binder implements IHotwordService { - private static final String DESCRIPTOR = "com.google.android.hotword.service.IHotwordService"; - static final int TRANSACTION_requestHotwordDetection = 1; + abstract class Stub extends Binder implements IHotwordService { + static final int TRANSACTION_requestHotwordDetection = 1; + private static final String DESCRIPTOR = "com.google.android.hotword.service.IHotwordService"; - public Stub() { - attachInterface(this, DESCRIPTOR); - } + public Stub() { + attachInterface(this, DESCRIPTOR); + } - public static IHotwordService asInterface(IBinder binder) { - if (binder == null) - return null; - IInterface iInterface = binder.queryLocalInterface(DESCRIPTOR); - if (iInterface != null && iInterface instanceof IHotwordService) - return (IHotwordService)iInterface; - return new Proxy(binder); - } + public static IHotwordService asInterface(IBinder binder) { + if (binder == null) + return null; + IInterface iInterface = binder.queryLocalInterface(DESCRIPTOR); + if (iInterface != null && iInterface instanceof IHotwordService) + return (IHotwordService) iInterface; + return new Proxy(binder); + } - public IBinder asBinder() { - return this; - } + public IBinder asBinder() { + return this; + } - public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { - switch (code) { - default: - return super.onTransact(code, data, reply, flags); - case INTERFACE_TRANSACTION: - reply.writeString(DESCRIPTOR); - return true; - case TRANSACTION_requestHotwordDetection: - data.enforceInterface(DESCRIPTOR); - String packageName = data.readString(); - boolean detect = (data.readInt() == 1) ? true : false; - requestHotwordDetection(packageName, detect); - return true; - } - } + public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { + switch (code) { + default: + return super.onTransact(code, data, reply, flags); + case INTERFACE_TRANSACTION: + reply.writeString(DESCRIPTOR); + return true; + case TRANSACTION_requestHotwordDetection: + data.enforceInterface(DESCRIPTOR); + String packageName = data.readString(); + boolean detect = data.readInt() == 1; + requestHotwordDetection(packageName, detect); + return true; + } + } - private static class Proxy implements IHotwordService { - private IBinder mRemote; + private static class Proxy implements IHotwordService { + private final IBinder mRemote; - Proxy(IBinder iBinder) { - mRemote = iBinder; - } + Proxy(IBinder iBinder) { + mRemote = iBinder; + } - public IBinder asBinder() { - return mRemote; - } + public IBinder asBinder() { + return mRemote; + } - public String getInterfaceDescriptor() { - return DESCRIPTOR; - } + public String getInterfaceDescriptor() { + return DESCRIPTOR; + } - public void requestHotwordDetection(String packageName, boolean detect) throws RemoteException { - Parcel data = Parcel.obtain(); - try { - data.writeInterfaceToken(getInterfaceDescriptor()); - data.writeString(packageName); - data.writeInt(detect ? 1 : 0); - mRemote.transact(TRANSACTION_requestHotwordDetection, data, null, FLAG_ONEWAY); - } finally { - data.recycle(); - } - } - } - } + public void requestHotwordDetection(String packageName, boolean detect) throws RemoteException { + Parcel data = Parcel.obtain(); + try { + data.writeInterfaceToken(getInterfaceDescriptor()); + data.writeString(packageName); + data.writeInt(detect ? 1 : 0); + mRemote.transact(TRANSACTION_requestHotwordDetection, data, null, FLAG_ONEWAY); + } finally { + data.recycle(); + } + } + } + } } \ No newline at end of file diff --git a/app/llx/app/src/main/java/com/mobeta/android/dslv/DragSortController.java b/app/llx/app/src/main/java/com/mobeta/android/dslv/DragSortController.java index 18ce671..e599070 100644 --- a/app/llx/app/src/main/java/com/mobeta/android/dslv/DragSortController.java +++ b/app/llx/app/src/main/java/com/mobeta/android/dslv/DragSortController.java @@ -13,7 +13,7 @@ import android.widget.AdapterView; * based on touch gestures. This class also inherits from * {@link SimpleFloatViewManager}, which provides basic float View * creation. - * + *

    * An instance of this class is meant to be passed to the methods * {@link DragSortListView#setTouchListener()} and * {@link DragSortListView#setFloatViewManager()} of your @@ -27,59 +27,62 @@ public class DragSortController extends SimpleFloatViewManager implements View.O public static final int ON_DOWN = 0; public static final int ON_DRAG = 1; public static final int ON_LONG_PRESS = 2; - - private int mDragInitMode = ON_DOWN; - - private boolean mSortEnabled = true; - /** * Remove mode enum. */ public static final int CLICK_REMOVE = 0; public static final int FLING_REMOVE = 1; - + public static final int MISS = -1; + private final GestureDetector mDetector; + private final GestureDetector mFlingRemoveDetector; + private final int mTouchSlop; + private final int[] mTempLoc = new int[2]; + private final float mFlingSpeed = 500f; + private final DragSortListView mDslv; + protected int mHitPos = MISS; + private int mDragInitMode = ON_DOWN; + private boolean mSortEnabled = true; /** * The current remove mode. */ private int mRemoveMode; - private boolean mRemoveEnabled = false; private boolean mIsRemoving = false; - - private GestureDetector mDetector; - - private GestureDetector mFlingRemoveDetector; - - private int mTouchSlop; - - public static final int MISS = -1; - - protected int mHitPos = MISS; private int mFlingHitPos = MISS; - private int mClickRemoveHitPos = MISS; - - private int[] mTempLoc = new int[2]; - private int mItemX; private int mItemY; - private int mCurrX; private int mCurrY; - private boolean mDragging = false; - - private float mFlingSpeed = 500f; - private int mDragHandleId; - private int mClickRemoveId; - private int mFlingHandleId; private boolean mCanDrag; - - private DragSortListView mDslv; private int mPositionX; + private final GestureDetector.OnGestureListener mFlingRemoveListener = + new GestureDetector.SimpleOnGestureListener() { + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, + float velocityY) { + // Log.d("mobeta", "on fling remove called"); + if (mRemoveEnabled && mIsRemoving) { + int w = mDslv.getWidth(); + int minPos = w / 5; + if (velocityX > mFlingSpeed) { + if (mPositionX > -minPos) { + mDslv.stopDragWithVelocity(true, velocityX); + } + } else if (velocityX < -mFlingSpeed) { + if (mPositionX < minPos) { + mDslv.stopDragWithVelocity(true, velocityX); + } + } + mIsRemoving = false; + } + return false; + } + }; /** * Calls {@link #DragSortController(DragSortListView, int)} with a @@ -101,15 +104,16 @@ public class DragSortController extends SimpleFloatViewManager implements View.O this(dslv, dragHandleId, dragInitMode, removeMode, clickRemoveId, 0); } + /** * By default, sorting is enabled, and removal is disabled. * - * @param dslv The DSLV instance + * @param dslv The DSLV instance * @param dragHandleId The resource id of the View that represents - * the drag handle in a list item. + * the drag handle in a list item. */ public DragSortController(DragSortListView dslv, int dragHandleId, int dragInitMode, - int removeMode, int clickRemoveId, int flingHandleId) { + int removeMode, int clickRemoveId, int flingHandleId) { super(dslv); mDslv = dslv; mDetector = new GestureDetector(dslv.getContext(), this); @@ -123,7 +127,6 @@ public class DragSortController extends SimpleFloatViewManager implements View.O setDragInitMode(dragInitMode); } - public int getDragInitMode() { return mDragInitMode; } @@ -138,19 +141,23 @@ public class DragSortController extends SimpleFloatViewManager implements View.O mDragInitMode = mode; } + public boolean isSortEnabled() { + return mSortEnabled; + } + /** * Enable/Disable list item sorting. Disabling is useful if only item * removal is desired. Prevents drags in the vertical direction. * * @param enabled Set true to enable list - * item sorting. + * item sorting. */ public void setSortEnabled(boolean enabled) { mSortEnabled = enabled; } - public boolean isSortEnabled() { - return mSortEnabled; + public int getRemoveMode() { + return mRemoveMode; } /** @@ -162,8 +169,8 @@ public class DragSortController extends SimpleFloatViewManager implements View.O mRemoveMode = mode; } - public int getRemoveMode() { - return mRemoveMode; + public boolean isRemoveEnabled() { + return mRemoveEnabled; } /** @@ -173,10 +180,6 @@ public class DragSortController extends SimpleFloatViewManager implements View.O mRemoveEnabled = enabled; } - public boolean isRemoveEnabled() { - return mRemoveEnabled; - } - /** * Set the resource id for the View that represents the drag * handle in a list item. @@ -213,9 +216,8 @@ public class DragSortController extends SimpleFloatViewManager implements View.O * Starts the drag on the DragSortListView. * * @param position The list item position (includes headers). - * @param deltaX Touch x-coord minus left edge of floating View. - * @param deltaY Touch y-coord minus top edge of floating View. - * + * @param deltaX Touch x-coord minus left edge of floating View. + * @param deltaY Touch y-coord minus top edge of floating View. * @return True if drag started, false otherwise. */ public boolean startDrag(int position, int deltaX, int deltaY) { @@ -295,7 +297,6 @@ public class DragSortController extends SimpleFloatViewManager implements View.O * event is detected. * * @param ev The ACTION_DOWN MotionEvent. - * * @return The list position to drag if a drag-init gesture is * detected; MISS if unsuccessful. */ @@ -313,7 +314,6 @@ public class DragSortController extends SimpleFloatViewManager implements View.O * if a drag handle touch was detected. * * @param ev The ACTION_DOWN MotionEvent. - * @return The list position of the item whose drag handle was * touched; MISS if unsuccessful. */ @@ -344,7 +344,7 @@ public class DragSortController extends SimpleFloatViewManager implements View.O final int rawX = (int) ev.getRawX(); final int rawY = (int) ev.getRawY(); - View dragBox = id == 0 ? item : (View) item.findViewById(id); + View dragBox = id == 0 ? item : item.findViewById(id); if (dragBox != null) { dragBox.getLocationOnScreen(mTempLoc); @@ -396,9 +396,7 @@ public class DragSortController extends SimpleFloatViewManager implements View.O if (mHitPos != MISS) { if (mDragInitMode == ON_DRAG && Math.abs(y2 - y1) > mTouchSlop && mSortEnabled) { startDrag(mHitPos, deltaX, deltaY); - } - else if (mDragInitMode != ON_DOWN && Math.abs(x2 - x1) > mTouchSlop && mRemoveEnabled) - { + } else if (mDragInitMode != ON_DOWN && Math.abs(x2 - x1) > mTouchSlop && mRemoveEnabled) { mIsRemoving = true; startDrag(mFlingHitPos, deltaX, deltaY); } @@ -408,7 +406,7 @@ public class DragSortController extends SimpleFloatViewManager implements View.O startDrag(mFlingHitPos, deltaX, deltaY); } else if (Math.abs(y2 - y1) > mTouchSlop) { mCanDrag = false; // if started to scroll the list then - // don't allow sorting nor fling-removing + // don't allow sorting nor fling-removing } } } @@ -420,7 +418,7 @@ public class DragSortController extends SimpleFloatViewManager implements View.O public void onLongPress(MotionEvent e) { // Log.d("mobeta", "lift listener long pressed"); if (mHitPos != MISS) { - if(mDragInitMode == ON_LONG_PRESS) { + if (mDragInitMode == ON_LONG_PRESS) { mDslv.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); startDrag(mHitPos, mCurrX - mItemX, mCurrY - mItemY); } else { @@ -432,7 +430,7 @@ public class DragSortController extends SimpleFloatViewManager implements View.O // complete the OnGestureListener interface @Override public final boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { - if(velocityX < 0 && Math.abs(velocityX) > Math.abs(velocityY)) { + if (velocityX < 0 && Math.abs(velocityX) > Math.abs(velocityY)) { onSwipeLeft(); return true; } @@ -458,28 +456,4 @@ public class DragSortController extends SimpleFloatViewManager implements View.O // do nothing } - private GestureDetector.OnGestureListener mFlingRemoveListener = - new GestureDetector.SimpleOnGestureListener() { - @Override - public final boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, - float velocityY) { - // Log.d("mobeta", "on fling remove called"); - if (mRemoveEnabled && mIsRemoving) { - int w = mDslv.getWidth(); - int minPos = w / 5; - if (velocityX > mFlingSpeed) { - if (mPositionX > -minPos) { - mDslv.stopDragWithVelocity(true, velocityX); - } - } else if (velocityX < -mFlingSpeed) { - if (mPositionX < minPos) { - mDslv.stopDragWithVelocity(true, velocityX); - } - } - mIsRemoving = false; - } - return false; - } - }; - } diff --git a/app/llx/app/src/main/java/com/mobeta/android/dslv/DragSortListView.java b/app/llx/app/src/main/java/com/mobeta/android/dslv/DragSortListView.java index 6b00ed7..7c0d54c 100644 --- a/app/llx/app/src/main/java/com/mobeta/android/dslv/DragSortListView.java +++ b/app/llx/app/src/main/java/com/mobeta/android/dslv/DragSortListView.java @@ -28,7 +28,6 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Point; import android.graphics.drawable.Drawable; -import android.os.Environment; import android.os.SystemClock; import android.util.AttributeSet; import android.util.Log; @@ -46,140 +45,40 @@ import android.widget.ListView; import net.pierrox.lightning_launcher_extreme.R; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; import java.util.ArrayList; /** * ListView subclass that mediates drag and drop resorting of items. - * - * - * @author heycosmo * + * @author heycosmo */ public class DragSortListView extends ListView { - - + + /** - * The View that floats above the ListView and represents - * the dragged item. + * Drag flag bit. Floating View can move in the positive + * x direction. */ - private View mFloatView; - + public final static int DRAG_POS_X = 0x1; /** - * The float View location. First based on touch location - * and given deltaX and deltaY. Then restricted by callback - * to FloatViewManager.onDragFloatView(). Finally restricted - * by bounds of DSLV. + * Drag flag bit. Floating View can move in the negative + * x direction. */ - private Point mFloatLoc = new Point(); - - private Point mTouchLoc = new Point(); - + public final static int DRAG_NEG_X = 0x2; /** - * The middle (in the y-direction) of the floating View. + * Drag flag bit. Floating View can move in the positive + * y direction. This is subtle. What this actually means is + * that, if enabled, the floating View can be dragged below its starting + * position. Remove in favor of upper-bounding item position? */ - private int mFloatViewMid; - + public final static int DRAG_POS_Y = 0x4; /** - * Flag to make sure float View isn't measured twice + * Drag flag bit. Floating View can move in the negative + * y direction. This is subtle. What this actually means is + * that the floating View can be dragged above its starting + * position. Remove in favor of lower-bounding item position? */ - private boolean mFloatViewOnMeasured = false; - - /** - * Watch the Adapter for data changes. Cancel a drag if - * coincident with a change. - */ - private DataSetObserver mObserver; - - /** - * Transparency for the floating View (XML attribute). - */ - private float mFloatAlpha = 0.7f; - private float mCurrFloatAlpha = 1.0f; - - /** - * While drag-sorting, the current position of the floating - * View. If dropped, the dragged item will land in this position. - */ - private int mFloatPos; - - /** - * The first expanded ListView position that helps represent - * the drop slot tracking the floating View. - */ - private int mFirstExpPos; - - /** - * The second expanded ListView position that helps represent - * the drop slot tracking the floating View. This can equal - * mFirstExpPos if there is no slide shuffle occurring; otherwise - * it is equal to mFirstExpPos + 1. - */ - private int mSecondExpPos; - - /** - * Flag set if slide shuffling is enabled. - */ - private boolean mAnimate = false; - - /** - * The user dragged from this position. - */ - private int mSrcPos; - - /** - * Offset (in x) within the dragged item at which the user - * picked it up (or first touched down with the digitalis). - */ - private int mDragDeltaX; - - /** - * Offset (in y) within the dragged item at which the user - * picked it up (or first touched down with the digitalis). - */ - private int mDragDeltaY; - - - /** - * The difference (in x) between screen coordinates and coordinates - * in this view. - */ - private int mOffsetX; - - /** - * The difference (in y) between screen coordinates and coordinates - * in this view. - */ - private int mOffsetY; - - /** - * A listener that receives callbacks whenever the floating View - * hovers over a new position. - */ - private DragListener mDragListener; - - /** - * A listener that receives a callback when the floating View - * is dropped. - */ - private DropListener mDropListener; - - /** - * A listener that receives a callback when the floating View - * (or more precisely the originally dragged item) is removed - * by one of the provided gestures. - */ - private RemoveListener mRemoveListener; - - /** - * Enable/Disable item dragging - * - * @attr name dslv:drag_enabled - */ - private boolean mDragEnabled = true; - + public final static int DRAG_NEG_Y = 0x8; /** * Drag state enum. */ @@ -188,175 +87,6 @@ public class DragSortListView extends ListView { private final static int DROPPING = 2; private final static int STOPPED = 3; private final static int DRAGGING = 4; - - private int mDragState = IDLE; - - /** - * Height in pixels to which the originally dragged item - * is collapsed during a drag-sort. Currently, this value - * must be greater than zero. - */ - private int mItemHeightCollapsed = 1; - - /** - * Height of the floating View. Stored for the purpose of - * providing the tracking drop slot. - */ - private int mFloatViewHeight; - - /** - * Convenience member. See above. - */ - private int mFloatViewHeightHalf; - - /** - * Save the given width spec for use in measuring children - */ - private int mWidthMeasureSpec = 0; - - /** - * Sample Views ultimately used for calculating the height - * of ListView items that are off-screen. - */ - private View[] mSampleViewTypes = new View[1]; - - /** - * Drag-scroll encapsulator! - */ - private DragScroller mDragScroller; - - /** - * Determines the start of the upward drag-scroll region - * at the top of the ListView. Specified by a fraction - * of the ListView height, thus screen resolution agnostic. - */ - private float mDragUpScrollStartFrac = 1.0f / 3.0f; - - /** - * Determines the start of the downward drag-scroll region - * at the bottom of the ListView. Specified by a fraction - * of the ListView height, thus screen resolution agnostic. - */ - private float mDragDownScrollStartFrac = 1.0f / 3.0f; - - /** - * The following are calculated from the above fracs. - */ - private int mUpScrollStartY; - private int mDownScrollStartY; - private float mDownScrollStartYF; - private float mUpScrollStartYF; - - /** - * Calculated from above above and current ListView height. - */ - private float mDragUpScrollHeight; - - /** - * Calculated from above above and current ListView height. - */ - private float mDragDownScrollHeight; - - /** - * Maximum drag-scroll speed in pixels per ms. Only used with - * default linear drag-scroll profile. - */ - private float mMaxScrollSpeed = 0.5f; - - /** - * Defines the scroll speed during a drag-scroll. User can - * provide their own; this default is a simple linear profile - * where scroll speed increases linearly as the floating View - * nears the top/bottom of the ListView. - */ - private DragScrollProfile mScrollProfile = new DragScrollProfile() { - @Override - public float getSpeed(float w, long t) { - return mMaxScrollSpeed * w; - } - }; - - /** - * Current touch x. - */ - private int mX; - - /** - * Current touch y. - */ - private int mY; - - /** - * Last touch x. - */ - private int mLastX; - - /** - * Last touch y. - */ - private int mLastY; - - /** - * The touch y-coord at which drag started - */ - private int mDragStartY; - - /** - * Drag flag bit. Floating View can move in the positive - * x direction. - */ - public final static int DRAG_POS_X = 0x1; - - /** - * Drag flag bit. Floating View can move in the negative - * x direction. - */ - public final static int DRAG_NEG_X = 0x2; - - /** - * Drag flag bit. Floating View can move in the positive - * y direction. This is subtle. What this actually means is - * that, if enabled, the floating View can be dragged below its starting - * position. Remove in favor of upper-bounding item position? - */ - public final static int DRAG_POS_Y = 0x4; - - /** - * Drag flag bit. Floating View can move in the negative - * y direction. This is subtle. What this actually means is - * that the floating View can be dragged above its starting - * position. Remove in favor of lower-bounding item position? - */ - public final static int DRAG_NEG_Y = 0x8; - - /** - * Flags that determine limits on the motion of the - * floating View. See flags above. - */ - private int mDragFlags = 0; - - /** - * Last call to an on*TouchEvent was a call to - * onInterceptTouchEvent. - */ - private boolean mLastCallWasIntercept = false; - - /** - * A touch event is in progress. - */ - private boolean mInTouchEvent = false; - - /** - * Let the user customize the floating View. - */ - private FloatViewManager mFloatViewManager = null; - - /** - * Given to ListView to cancel its action when a drag-sort - * begins. - */ - private MotionEvent mCancelEvent; - /** * Enum telling where to cancel the ListView action when a * drag-sort begins @@ -364,59 +94,6 @@ public class DragSortListView extends ListView { private static final int NO_CANCEL = 0; private static final int ON_TOUCH_EVENT = 1; private static final int ON_INTERCEPT_TOUCH_EVENT = 2; - - /** - * Where to cancel the ListView action when a - * drag-sort begins - */ - private int mCancelMethod = NO_CANCEL; - - /** - * Determines when a slide shuffle animation starts. That is, - * defines how close to the edge of the drop slot the floating - * View must be to initiate the slide. - */ - private float mSlideRegionFrac = 0.25f; - - /** - * Number between 0 and 1 indicating the relative location of - * a sliding item (only used if drag-sort animations - * are turned on). Nearly 1 means the item is - * at the top of the slide region (nearly full blank item - * is directly below). - */ - private float mSlideFrac = 0.0f; - - /** - * Wraps the user-provided ListAdapter. This is used to wrap each - * item View given by the user inside another View (currenly - * a RelativeLayout) which - * expands and collapses to simulate the item shuffling. - */ - private AdapterWrapper mAdapterWrapper; - - /** - * Turn on custom debugger. - */ -// private boolean mTrackDragSort = false; - - /** - * Debugging class. - */ -// private DragSortTracker mDragSortTracker; - - /** - * Needed for adjusting item heights from within layoutChildren - */ - private boolean mBlockLayoutRequests = false; - - /** - * Set to true when a down event happens during drag sort; - * for example, when drag finish animations are - * playing. - */ - private boolean mIgnoreTouchEvent = false; - /** * Caches DragSortItemView child heights. Sometimes DSLV has to * know the height of an offscreen item. Since ListView virtualizes @@ -429,8 +106,267 @@ public class DragSortListView extends ListView { * drag-sort. */ private static final int sCacheSize = 3; - private HeightCache mChildHeightCache = new HeightCache(sCacheSize); + /** + * The float View location. First based on touch location + * and given deltaX and deltaY. Then restricted by callback + * to FloatViewManager.onDragFloatView(). Finally restricted + * by bounds of DSLV. + */ + private final Point mFloatLoc = new Point(); + private final Point mTouchLoc = new Point(); + /** + * Watch the Adapter for data changes. Cancel a drag if + * coincident with a change. + */ + private final DataSetObserver mObserver; + /** + * Drag-scroll encapsulator! + */ + private final DragScroller mDragScroller; + /** + * Given to ListView to cancel its action when a drag-sort + * begins. + */ + private final MotionEvent mCancelEvent; + private final HeightCache mChildHeightCache = new HeightCache(sCacheSize); + /** + * The View that floats above the ListView and represents + * the dragged item. + */ + private View mFloatView; + /** + * The middle (in the y-direction) of the floating View. + */ + private int mFloatViewMid; + /** + * Flag to make sure float View isn't measured twice + */ + private boolean mFloatViewOnMeasured = false; + /** + * Transparency for the floating View (XML attribute). + */ + private float mFloatAlpha = 0.7f; + private float mCurrFloatAlpha = 1.0f; + /** + * While drag-sorting, the current position of the floating + * View. If dropped, the dragged item will land in this position. + */ + private int mFloatPos; + /** + * The first expanded ListView position that helps represent + * the drop slot tracking the floating View. + */ + private int mFirstExpPos; + /** + * The second expanded ListView position that helps represent + * the drop slot tracking the floating View. This can equal + * mFirstExpPos if there is no slide shuffle occurring; otherwise + * it is equal to mFirstExpPos + 1. + */ + private int mSecondExpPos; + /** + * Flag set if slide shuffling is enabled. + */ + private boolean mAnimate = false; + /** + * The user dragged from this position. + */ + private int mSrcPos; + /** + * Offset (in x) within the dragged item at which the user + * picked it up (or first touched down with the digitalis). + */ + private int mDragDeltaX; + /** + * Offset (in y) within the dragged item at which the user + * picked it up (or first touched down with the digitalis). + */ + private int mDragDeltaY; + /** + * The difference (in x) between screen coordinates and coordinates + * in this view. + */ + private int mOffsetX; + /** + * The difference (in y) between screen coordinates and coordinates + * in this view. + */ + private int mOffsetY; + /** + * A listener that receives callbacks whenever the floating View + * hovers over a new position. + */ + private DragListener mDragListener; + /** + * A listener that receives a callback when the floating View + * is dropped. + */ + private DropListener mDropListener; + /** + * A listener that receives a callback when the floating View + * (or more precisely the originally dragged item) is removed + * by one of the provided gestures. + */ + private RemoveListener mRemoveListener; + /** + * Enable/Disable item dragging + * + * @attr name dslv:drag_enabled + */ + private boolean mDragEnabled = true; + private int mDragState = IDLE; + /** + * Height in pixels to which the originally dragged item + * is collapsed during a drag-sort. Currently, this value + * must be greater than zero. + */ + private int mItemHeightCollapsed = 1; + /** + * Height of the floating View. Stored for the purpose of + * providing the tracking drop slot. + */ + private int mFloatViewHeight; + /** + * Convenience member. See above. + */ + private int mFloatViewHeightHalf; + /** + * Save the given width spec for use in measuring children + */ + private int mWidthMeasureSpec = 0; + /** + * Sample Views ultimately used for calculating the height + * of ListView items that are off-screen. + */ + private View[] mSampleViewTypes = new View[1]; + /** + * Determines the start of the upward drag-scroll region + * at the top of the ListView. Specified by a fraction + * of the ListView height, thus screen resolution agnostic. + */ + private float mDragUpScrollStartFrac = 1.0f / 3.0f; + /** + * Determines the start of the downward drag-scroll region + * at the bottom of the ListView. Specified by a fraction + * of the ListView height, thus screen resolution agnostic. + */ + private float mDragDownScrollStartFrac = 1.0f / 3.0f; + /** + * The following are calculated from the above fracs. + */ + private int mUpScrollStartY; + private int mDownScrollStartY; + private float mDownScrollStartYF; + private float mUpScrollStartYF; + /** + * Calculated from above above and current ListView height. + */ + private float mDragUpScrollHeight; + /** + * Calculated from above above and current ListView height. + */ + private float mDragDownScrollHeight; + /** + * Maximum drag-scroll speed in pixels per ms. Only used with + * default linear drag-scroll profile. + */ + private float mMaxScrollSpeed = 0.5f; + /** + * Defines the scroll speed during a drag-scroll. User can + * provide their own; this default is a simple linear profile + * where scroll speed increases linearly as the floating View + * nears the top/bottom of the ListView. + */ + private DragScrollProfile mScrollProfile = new DragScrollProfile() { + @Override + public float getSpeed(float w, long t) { + return mMaxScrollSpeed * w; + } + }; + /** + * Current touch x. + */ + private int mX; + /** + * Current touch y. + */ + private int mY; + /** + * Last touch x. + */ + private int mLastX; + /** + * Last touch y. + */ + private int mLastY; + /** + * The touch y-coord at which drag started + */ + private int mDragStartY; + /** + * Flags that determine limits on the motion of the + * floating View. See flags above. + */ + private int mDragFlags = 0; + /** + * Last call to an on*TouchEvent was a call to + * onInterceptTouchEvent. + */ + private boolean mLastCallWasIntercept = false; + /** + * A touch event is in progress. + */ + private boolean mInTouchEvent = false; + /** + * Let the user customize the floating View. + */ + private FloatViewManager mFloatViewManager = null; + /** + * Where to cancel the ListView action when a + * drag-sort begins + */ + private int mCancelMethod = NO_CANCEL; + /** + * Determines when a slide shuffle animation starts. That is, + * defines how close to the edge of the drop slot the floating + * View must be to initiate the slide. + */ + private float mSlideRegionFrac = 0.25f; + /** + * Turn on custom debugger. + */ +// private boolean mTrackDragSort = false; + + /** + * Debugging class. + */ +// private DragSortTracker mDragSortTracker; + /** + * Number between 0 and 1 indicating the relative location of + * a sliding item (only used if drag-sort animations + * are turned on). Nearly 1 means the item is + * at the top of the slide region (nearly full blank item + * is directly below). + */ + private float mSlideFrac = 0.0f; + /** + * Wraps the user-provided ListAdapter. This is used to wrap each + * item View given by the user inside another View (currenly + * a RelativeLayout) which + * expands and collapses to simulate the item shuffling. + */ + private AdapterWrapper mAdapterWrapper; + /** + * Needed for adjusting item heights from within layoutChildren + */ + private boolean mBlockLayoutRequests = false; + /** + * Set to true when a down event happens during drag sort; + * for example, when drag finish animations are + * playing. + */ + private boolean mIgnoreTouchEvent = false; private RemoveAnimator mRemoveAnimator; private LiftAnimator mLiftAnimator; @@ -439,6 +375,8 @@ public class DragSortListView extends ListView { private boolean mUseRemoveVelocity; private float mRemoveVelocityX = 0; + private boolean mListViewIntercepted = false; + private boolean mFloatViewInvalidated = false; public DragSortListView(Context context, AttributeSet attrs) { super(context, attrs); @@ -570,6 +508,94 @@ public class DragSortListView extends ListView { }; } + private static int buildRunList(SparseBooleanArray cip, int rangeStart, + int rangeEnd, int[] runStart, int[] runEnd) { + int runCount = 0; + + int i = findFirstSetIndex(cip, rangeStart, rangeEnd); + if (i == -1) + return 0; + + int position = cip.keyAt(i); + int currentRunStart = position; + int currentRunEnd = currentRunStart + 1; + for (i++; i < cip.size() && (position = cip.keyAt(i)) < rangeEnd; i++) { + if (!cip.valueAt(i)) // not checked => not interesting + continue; + if (position == currentRunEnd) { + currentRunEnd++; + } else { + runStart[runCount] = currentRunStart; + runEnd[runCount] = currentRunEnd; + runCount++; + currentRunStart = position; + currentRunEnd = position + 1; + } + } + + if (currentRunEnd == rangeEnd) { + // rangeStart and rangeEnd are equivalent positions so to be + // consistent we translate them to the same integer value. That way + // we can check whether a run covers the entire range by just + // checking if the start equals the end position. + currentRunEnd = rangeStart; + } + runStart[runCount] = currentRunStart; + runEnd[runCount] = currentRunEnd; + runCount++; + + if (runCount > 1) { + if (runStart[0] == rangeStart && runEnd[runCount - 1] == rangeStart) { + // The last run ends at the end of the range, and the first run + // starts at the beginning of the range. So they are actually + // part of the same run, except they wrap around the end of the + // range. To avoid adjacent runs, we need to merge them. + runStart[0] = runStart[runCount - 1]; + runCount--; + } + } + return runCount; + } + + private static int rotate(int value, int offset, int lowerBound, int upperBound) { + int windowSize = upperBound - lowerBound; + + value += offset; + if (value < lowerBound) { + value += windowSize; + } else if (value >= upperBound) { + value -= windowSize; + } + return value; + } + + private static int findFirstSetIndex(SparseBooleanArray sba, int rangeStart, int rangeEnd) { + int size = sba.size(); + int i = insertionIndexForKey(sba, rangeStart); + while (i < size && sba.keyAt(i) < rangeEnd && !sba.valueAt(i)) + i++; + if (i == size || sba.keyAt(i) >= rangeEnd) + return -1; + return i; + } + + private static int insertionIndexForKey(SparseBooleanArray sba, int key) { + int low = 0; + int high = sba.size(); + while (high - low > 0) { + int middle = (low + high) >> 1; + if (sba.keyAt(middle) < key) + low = middle + 1; + else + high = middle; + } + return low; + } + + public float getFloatAlpha() { + return mCurrFloatAlpha; + } + /** * Usually called from a FloatViewManager. The float alpha * will be reset to the xml-defined value every time a drag @@ -579,14 +605,10 @@ public class DragSortListView extends ListView { mCurrFloatAlpha = alpha; } - public float getFloatAlpha() { - return mCurrFloatAlpha; - } - /** * Set maximum drag scroll speed in positions/second. Only applies * if using default ScrollSpeedProfile. - * + * * @param max Maximum scroll speed. */ public void setMaxScrollSpeed(float max) { @@ -597,10 +619,9 @@ public class DragSortListView extends ListView { * For each DragSortListView Listener interface implemented by * adapter, this method calls the appropriate * set*Listener method with adapter as the argument. - * - * @param adapter The ListAdapter providing data to back - * DragSortListView. * + * @param adapter The ListAdapter providing data to back + * DragSortListView. * @see android.widget.ListView#setAdapter(android.widget.ListAdapter) */ @Override @@ -640,115 +661,6 @@ public class DragSortListView extends ListView { } } - private class AdapterWrapper extends BaseAdapter { - private ListAdapter mAdapter; - - public AdapterWrapper(ListAdapter adapter) { - super(); - mAdapter = adapter; - - mAdapter.registerDataSetObserver(new DataSetObserver() { - public void onChanged() { - notifyDataSetChanged(); - } - - public void onInvalidated() { - notifyDataSetInvalidated(); - } - }); - } - - public ListAdapter getAdapter() { - return mAdapter; - } - - @Override - public long getItemId(int position) { - return mAdapter.getItemId(position); - } - - @Override - public Object getItem(int position) { - return mAdapter.getItem(position); - } - - @Override - public int getCount() { - return mAdapter.getCount(); - } - - @Override - public boolean areAllItemsEnabled() { - return mAdapter.areAllItemsEnabled(); - } - - @Override - public boolean isEnabled(int position) { - return mAdapter.isEnabled(position); - } - - @Override - public int getItemViewType(int position) { - return mAdapter.getItemViewType(position); - } - - @Override - public int getViewTypeCount() { - return mAdapter.getViewTypeCount(); - } - - @Override - public boolean hasStableIds() { - return mAdapter.hasStableIds(); - } - - @Override - public boolean isEmpty() { - return mAdapter.isEmpty(); - } - - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - - DragSortItemView v; - View child; - // Log.d("mobeta", - // "getView: position="+position+" convertView="+convertView); - if (convertView != null) { - v = (DragSortItemView) convertView; - View oldChild = v.getChildAt(0); - - child = mAdapter.getView(position, oldChild, DragSortListView.this); - if (child != oldChild) { - // shouldn't get here if user is reusing convertViews - // properly - if (oldChild != null) { - v.removeViewAt(0); - } - v.addView(child); - } - } else { - child = mAdapter.getView(position, null, DragSortListView.this); - if (child instanceof Checkable) { - v = new DragSortItemViewCheckable(getContext()); - } else { - v = new DragSortItemView(getContext()); - } - v.setLayoutParams(new AbsListView.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT)); - v.addView(child); - } - - // Set the correct item height given drag state; passed - // View needs to be measured if measurement is required. - adjustItem(position + getHeaderViewsCount(), v, true); - - return v; - } - } - private void drawDivider(int expPosition, Canvas canvas) { final Drawable divider = getDivider(); @@ -850,49 +762,6 @@ public class DragSortListView extends ListView { + mSecondExpPos); } - private class HeightCache { - - private SparseIntArray mMap; - private ArrayList mOrder; - private int mMaxSize; - - public HeightCache(int size) { - mMap = new SparseIntArray(size); - mOrder = new ArrayList(size); - mMaxSize = size; - } - - /** - * Add item height at position if doesn't already exist. - */ - public void add(int position, int height) { - int currHeight = mMap.get(position, -1); - if (currHeight != height) { - if (currHeight == -1) { - if (mMap.size() == mMaxSize) { - // remove oldest entry - mMap.delete(mOrder.remove(0)); - } - } else { - // move position to newest slot - mOrder.remove((Integer) position); - } - mMap.put(position, height); - mOrder.add(position); - } - } - - public int get(int position) { - return mMap.get(position, -1); - } - - public void clear() { - mMap.clear(); - mOrder.clear(); - } - - } - /** * Get the shuffle edge for item at position when top of * item is at y-coord top. Assumes that current item heights @@ -903,9 +772,8 @@ public class DragSortListView extends ListView { * * @param position * @param top - * @param height Height of item at position. If -1, this function - * calculates this height. - * + * @param height Height of item at position. If -1, this function + * calculates this height. * @return Shuffle line between position-1 and position (for * the given view of the list; that is, for when top of item at * position has y-coord of given `top`). If @@ -1076,11 +944,13 @@ public class DragSortListView extends ListView { mSlideFrac = 0.5f * ((float) (slideEdgeTop - mFloatViewMid)) / slideRgnHeightF; // Log.d("mobeta", // "firstExp="+mFirstExpPos+" secExp="+mSecondExpPos+" slideFrac="+mSlideFrac); - if(mDragState == DRAGGING && mDragListener != null) mDragListener.onItemHovered(itemPos + (itemPos>mSrcPos ? 0 : -1)); + if (mDragState == DRAGGING && mDragListener != null) + mDragListener.onItemHovered(itemPos + (itemPos > mSrcPos ? 0 : -1)); } else if (mFloatViewMid < slideEdgeBottom) { mFirstExpPos = itemPos; mSecondExpPos = itemPos; - if(mDragState == DRAGGING && mDragListener != null) mDragListener.onItemHovered(-1); + if (mDragState == DRAGGING && mDragListener != null) + mDragListener.onItemHovered(-1); } else { mFirstExpPos = itemPos; mSecondExpPos = itemPos + 1; @@ -1088,7 +958,8 @@ public class DragSortListView extends ListView { / slideRgnHeightF); // Log.d("mobeta", // "firstExp="+mFirstExpPos+" secExp="+mSecondExpPos+" slideFrac="+mSlideFrac); - if(mDragState == DRAGGING && mDragListener != null) mDragListener.onItemHovered(itemPos + (itemPos>=mSrcPos ? 1 : 0)); + if (mDragState == DRAGGING && mDragListener != null) + mDragListener.onItemHovered(itemPos + (itemPos >= mSrcPos ? 1 : 0)); } } else { @@ -1133,275 +1004,6 @@ public class DragSortListView extends ListView { // } } - private class SmoothAnimator implements Runnable { - protected long mStartTime; - - private float mDurationF; - - private float mAlpha; - private float mA, mB, mC, mD; - - private boolean mCanceled; - - public SmoothAnimator(float smoothness, int duration) { - mAlpha = smoothness; - mDurationF = (float) duration; - mA = mD = 1f / (2f * mAlpha * (1f - mAlpha)); - mB = mAlpha / (2f * (mAlpha - 1f)); - mC = 1f / (1f - mAlpha); - } - - public float transform(float frac) { - if (frac < mAlpha) { - return mA * frac * frac; - } else if (frac < 1f - mAlpha) { - return mB + mC * frac; - } else { - return 1f - mD * (frac - 1f) * (frac - 1f); - } - } - - public void start() { - mStartTime = SystemClock.uptimeMillis(); - mCanceled = false; - onStart(); - post(this); - } - - public void cancel() { - mCanceled = true; - } - - public void onStart() { - // stub - } - - public void onUpdate(float frac, float smoothFrac) { - // stub - } - - public void onStop() { - // stub - } - - @Override - public void run() { - if (mCanceled) { - return; - } - - float fraction = ((float) (SystemClock.uptimeMillis() - mStartTime)) / mDurationF; - - if (fraction >= 1f) { - onUpdate(1f, 1f); - onStop(); - } else { - onUpdate(fraction, transform(fraction)); - post(this); - } - } - } - - /** - * Centers floating View under touch point. - */ - private class LiftAnimator extends SmoothAnimator { - - private float mInitDragDeltaY; - private float mFinalDragDeltaY; - - public LiftAnimator(float smoothness, int duration) { - super(smoothness, duration); - } - - @Override - public void onStart() { - mInitDragDeltaY = mDragDeltaY; - mFinalDragDeltaY = mFloatViewHeightHalf; - } - - @Override - public void onUpdate(float frac, float smoothFrac) { - if (mDragState != DRAGGING) { - cancel(); - } else { - mDragDeltaY = (int) (smoothFrac * mFinalDragDeltaY + (1f - smoothFrac) - * mInitDragDeltaY); - mFloatLoc.y = mY - mDragDeltaY; - doDragFloatView(true); - } - } - } - - /** - * Centers floating View over drop slot before destroying. - */ - private class DropAnimator extends SmoothAnimator { - - private int mDropPos; - private int srcPos; - private float mInitDeltaY; - private float mInitDeltaX; - - public DropAnimator(float smoothness, int duration) { - super(smoothness, duration); - } - - @Override - public void onStart() { - mDropPos = mFloatPos; - srcPos = mSrcPos; - mDragState = DROPPING; - mInitDeltaY = mFloatLoc.y - getTargetY(); - mInitDeltaX = mFloatLoc.x - getPaddingLeft(); - } - - private int getTargetY() { - final int first = getFirstVisiblePosition(); - final int otherAdjust = (mItemHeightCollapsed + getDividerHeight()) / 2; - View v = getChildAt(mDropPos - first); - int targetY = -1; - if (v != null) { - if (mDropPos == srcPos) { - targetY = v.getTop(); - } else if (mDropPos < srcPos) { - // expanded down - targetY = v.getTop() - otherAdjust; - } else { - // expanded up - targetY = v.getBottom() + otherAdjust - mFloatViewHeight; - } - } else { - // drop position is not on screen?? no animation - cancel(); - } - - return targetY; - } - - @Override - public void onUpdate(float frac, float smoothFrac) { - final int targetY = getTargetY(); - final int targetX = getPaddingLeft(); - final float deltaY = mFloatLoc.y - targetY; - final float deltaX = mFloatLoc.x - targetX; - final float f = 1f - smoothFrac; - if (f < Math.abs(deltaY / mInitDeltaY) || f < Math.abs(deltaX / mInitDeltaX)) { - mFloatLoc.y = targetY + (int) (mInitDeltaY * f); - mFloatLoc.x = getPaddingLeft() + (int) (mInitDeltaX * f); - doDragFloatView(true); - } - } - - @Override - public void onStop() { - dropFloatView(); - } - - } - - /** - * Collapses expanded items. - */ - private class RemoveAnimator extends SmoothAnimator { - - private float mFloatLocX; - private float mFirstStartBlank; - private float mSecondStartBlank; - - private int mFirstChildHeight = -1; - private int mSecondChildHeight = -1; - - private int mFirstPos; - private int mSecondPos; - private int srcPos; - - public RemoveAnimator(float smoothness, int duration) { - super(smoothness, duration); - } - - @Override - public void onStart() { - mFirstChildHeight = -1; - mSecondChildHeight = -1; - mFirstPos = mFirstExpPos; - mSecondPos = mSecondExpPos; - srcPos = mSrcPos; - mDragState = REMOVING; - - mFloatLocX = mFloatLoc.x; - if (mUseRemoveVelocity) { - float minVelocity = 2f * getWidth(); - if (mRemoveVelocityX == 0) { - mRemoveVelocityX = (mFloatLocX < 0 ? -1 : 1) * minVelocity; - } else { - minVelocity *= 2; - if (mRemoveVelocityX < 0 && mRemoveVelocityX > -minVelocity) - mRemoveVelocityX = -minVelocity; - else if (mRemoveVelocityX > 0 && mRemoveVelocityX < minVelocity) - mRemoveVelocityX = minVelocity; - } - } else { - destroyFloatView(); - } - } - - @Override - public void onUpdate(float frac, float smoothFrac) { - float f = 1f - smoothFrac; - - final int firstVis = getFirstVisiblePosition(); - View item = getChildAt(mFirstPos - firstVis); - ViewGroup.LayoutParams lp; - int blank; - - if (mUseRemoveVelocity) { - float dt = (float) (SystemClock.uptimeMillis() - mStartTime) / 1000; - if (dt == 0) - return; - float dx = mRemoveVelocityX * dt; - int w = getWidth(); - mRemoveVelocityX += (mRemoveVelocityX > 0 ? 1 : -1) * dt * w; - mFloatLocX += dx; - mFloatLoc.x = (int) mFloatLocX; - if (mFloatLocX < w && mFloatLocX > -w) { - mStartTime = SystemClock.uptimeMillis(); - doDragFloatView(true); - return; - } - } - - if (item != null) { - if (mFirstChildHeight == -1) { - mFirstChildHeight = getChildHeight(mFirstPos, item, false); - mFirstStartBlank = (float) (item.getHeight() - mFirstChildHeight); - } - blank = Math.max((int) (f * mFirstStartBlank), 1); - lp = item.getLayoutParams(); - lp.height = mFirstChildHeight + blank; - item.setLayoutParams(lp); - } - if (mSecondPos != mFirstPos) { - item = getChildAt(mSecondPos - firstVis); - if (item != null) { - if (mSecondChildHeight == -1) { - mSecondChildHeight = getChildHeight(mSecondPos, item, false); - mSecondStartBlank = (float) (item.getHeight() - mSecondChildHeight); - } - blank = Math.max((int) (f * mSecondStartBlank), 1); - lp = item.getLayoutParams(); - lp.height = mSecondChildHeight + blank; - item.setLayoutParams(lp); - } - } - } - - @Override - public void onStop() { - doRemoveItem(); - } - } - public void removeItem(int which) { mUseRemoveVelocity = false; @@ -1411,8 +1013,8 @@ public class DragSortListView extends ListView { /** * Removes an item from the list and animates the removal. * - * @param which Position to remove (NOTE: headers/footers ignored! - * this is a position in your input ListAdapter). + * @param which Position to remove (NOTE: headers/footers ignored! + * this is a position in your input ListAdapter). * @param velocityX */ public void removeItem(int which, float velocityX) { @@ -1457,9 +1059,9 @@ public class DragSortListView extends ListView { * through to {@link DropListener#drop(int, int)}. * * @param from Position to move (NOTE: headers/footers ignored! - * this is a position in your input ListAdapter). - * @param to Target position (NOTE: headers/footers ignored! - * this is a position in your input ListAdapter). + * this is a position in your input ListAdapter). + * @param to Target position (NOTE: headers/footers ignored! + * this is a position in your input ListAdapter). */ public void moveItem(int from, int to) { if (mDropListener != null) { @@ -1571,9 +1173,8 @@ public class DragSortListView extends ListView { * like to remove the dragged item from the list. * * @param remove Remove the dragged item from the list. Calls - * a registered RemoveListener, if one exists. Otherwise, calls - * the DropListener, if one exists. - * + * a registered RemoveListener, if one exists. Otherwise, calls + * the DropListener, if one exists. * @return True if the stop was successful. False if there is * no floating View. */ @@ -1696,8 +1297,6 @@ public class DragSortListView extends ListView { return mListViewIntercepted; } - private boolean mListViewIntercepted = false; - @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if (!mDragEnabled) { @@ -1756,8 +1355,7 @@ public class DragSortListView extends ListView { * a fraction of the ListView height. * * @param heightFraction Fraction of ListView height. Capped at - * 0.5f. - * + * 0.5f. */ public void setDragScrollStart(float heightFraction) { setDragScrollStarts(heightFraction, heightFraction); @@ -1768,10 +1366,9 @@ public class DragSortListView extends ListView { * a fraction of the ListView height. * * @param upperFrac Fraction of ListView height for up-scroll bound. - * Capped at 0.5f. + * Capped at 0.5f. * @param lowerFrac Fraction of ListView height for down-scroll bound. - * Capped at 0.5f. - * + * Capped at 0.5f. */ public void setDragScrollStarts(float upperFrac, float lowerFrac) { if (lowerFrac > 0.5f) { @@ -1827,8 +1424,7 @@ public class DragSortListView extends ListView { // start scrolling up mDragScroller.startScrolling(DragScroller.UP); - } - else if (maxY >= mUpScrollStartY && minY <= mDownScrollStartY + } else if (maxY >= mUpScrollStartY && minY <= mDownScrollStartY && mDragScroller.isScrolling()) { // not in the upper nor in the lower drag-scroll regions but it is // still scrolling @@ -2178,8 +1774,6 @@ public class DragSortListView extends ListView { return true; } - private boolean mFloatViewInvalidated = false; - private void invalidateFloatView() { mFloatViewInvalidated = true; } @@ -2187,21 +1781,20 @@ public class DragSortListView extends ListView { /** * Start a drag of item at position using the * registered FloatViewManager. Calls through - * to {@link #startDrag(int,View,int,int,int)} after obtaining + * to {@link #startDrag(int, View, int, int, int)} after obtaining * the floating View from the FloatViewManager. * - * @param position Item to drag. + * @param position Item to drag. * @param dragFlags Flags that restrict some movements of the - * floating View. For example, set dragFlags |= - * ~{@link #DRAG_NEG_X} to allow dragging the floating - * View in all directions except off the screen to the left. - * @param deltaX Offset in x of the touch coordinate from the - * left edge of the floating View (i.e. touch-x minus float View - * left). - * @param deltaY Offset in y of the touch coordinate from the - * top edge of the floating View (i.e. touch-y minus float View - * top). - * + * floating View. For example, set dragFlags |= + * ~{@link #DRAG_NEG_X} to allow dragging the floating + * View in all directions except off the screen to the left. + * @param deltaX Offset in x of the touch coordinate from the + * left edge of the floating View (i.e. touch-x minus float View + * left). + * @param deltaY Offset in y of the touch coordinate from the + * top edge of the floating View (i.e. touch-y minus float View + * top). * @return True if the drag was started, false otherwise. This * startDrag will fail if we are not currently in * a touch event, there is no registered FloatViewManager, @@ -2226,19 +1819,18 @@ public class DragSortListView extends ListView { * Start a drag of item at position without using * a FloatViewManager. * - * @param position Item to drag. + * @param position Item to drag. * @param floatView Floating View. * @param dragFlags Flags that restrict some movements of the - * floating View. For example, set dragFlags |= - * ~{@link #DRAG_NEG_X} to allow dragging the floating - * View in all directions except off the screen to the left. - * @param deltaX Offset in x of the touch coordinate from the - * left edge of the floating View (i.e. touch-x minus float View - * left). - * @param deltaY Offset in y of the touch coordinate from the - * top edge of the floating View (i.e. touch-y minus float View - * top). - * + * floating View. For example, set dragFlags |= + * ~{@link #DRAG_NEG_X} to allow dragging the floating + * View in all directions except off the screen to the left. + * @param deltaX Offset in x of the touch coordinate from the + * left edge of the floating View (i.e. touch-x minus float View + * left). + * @param deltaY Offset in y of the touch coordinate from the + * top edge of the floating View (i.e. touch-y minus float View + * top). * @return True if the drag was started, false otherwise. This * startDrag will fail if we are not currently in * a touch event, floatView is null, or there is @@ -2420,59 +2012,6 @@ public class DragSortListView extends ListView { } } - /** - * Interface for customization of the floating View appearance - * and dragging behavior. Implement - * your own and pass it to {@link #setFloatViewManager}. If - * your own is not passed, the default {@link SimpleFloatViewManager} - * implementation is used. - */ - public interface FloatViewManager { - /** - * Return the floating View for item at position. - * DragSortListView will measure and layout this View for you, - * so feel free to just inflate it. You can help DSLV by - * setting some {@link ViewGroup.LayoutParams} on this View; - * otherwise it will set some for you (with a width of FILL_PARENT - * and a height of WRAP_CONTENT). - * - * @param position Position of item to drag (NOTE: - * position excludes header Views; thus, if you - * want to call {@link ListView#getChildAt(int)}, you will need - * to add {@link ListView#getHeaderViewsCount()} to the index). - * - * @return The View you wish to display as the floating View. - */ - public View onCreateFloatView(int position); - - /** - * Called whenever the floating View is dragged. Float View - * properties can be changed here. Also, the upcoming location - * of the float View can be altered by setting - * location.x and location.y. - * - * @param floatView The floating View. - * @param location The location (top-left; relative to DSLV - * top-left) at which the float - * View would like to appear, given the current touch location - * and the offset provided in {@link DragSortListView#startDrag}. - * @param touch The current touch location (relative to DSLV - * top-left). - * @param pendingScroll - */ - public void onDragFloatView(View floatView, Point location, Point touch); - - /** - * Called when the float View is dropped; lets you perform - * any necessary cleanup. The internal DSLV floating View - * reference is set to null immediately after this is called. - * - * @param floatView The floating View passed to - * {@link #onCreateFloatView(int)}. - */ - public void onDestroyFloatView(View floatView); - } - public void setFloatViewManager(FloatViewManager manager) { mFloatViewManager = manager; } @@ -2481,6 +2020,10 @@ public class DragSortListView extends ListView { mDragListener = l; } + public boolean isDragEnabled() { + return mDragEnabled; + } + /** * Allows for easy toggling between a DragSortListView * and a regular old ListView. If enabled, items are @@ -2489,16 +2032,12 @@ public class DragSortListView extends ListView { * If disabled, items cannot be dragged. * * @param enabled Set true to enable list - * item dragging + * item dragging */ public void setDragEnabled(boolean enabled) { mDragEnabled = enabled; } - public boolean isDragEnabled() { - return mDragEnabled; - } - /** * This better reorder your ListAdapter! DragSortListView does not do this * for you; doesn't make sense to. Make sure @@ -2529,39 +2068,6 @@ public class DragSortListView extends ListView { mRemoveListener = l; } - public interface DragListener { - public void drag(int from, int to); - public void onItemHovered(int position); - } - - /** - * Your implementation of this has to reorder your ListAdapter! - * Make sure to call - * {@link BaseAdapter#notifyDataSetChanged()} or something like it - * in your implementation. - * - * @author heycosmo - * - */ - public interface DropListener { - public void drop(int from, int to); - } - - /** - * Make sure to call - * {@link BaseAdapter#notifyDataSetChanged()} or something like it - * in your implementation. - * - * @author heycosmo - * - */ - public interface RemoveListener { - public void remove(int which); - } - - public interface DragSortListener extends DropListener, DragListener, RemoveListener { - } - public void setDragSortListener(DragSortListener l) { setDropListener(l); setDragListener(l); @@ -2572,7 +2078,7 @@ public class DragSortListView extends ListView { * Completely custom scroll speed profile. Default increases linearly * with position and is constant in time. Create your own by implementing * {@link DragSortListView.DragScrollProfile}. - * + * * @param ssp */ public void setDragScrollProfile(DragScrollProfile ssp) { @@ -2603,7 +2109,7 @@ public class DragSortListView extends ListView { * the user will move items more than 20 rows away from the original * position, you may wish to use an adapter with unstable IDs and call this * method manually instead. - * + * * @param from * @param to */ @@ -2674,9 +2180,9 @@ public class DragSortListView extends ListView { * {@link ListAdapter#hasStableIds()}). This is because without IDs, the * ListView has no way of knowing which items have moved where, and cannot * update the check state accordingly. - * + *

    * See also further comments on {@link #moveCheckState(int, int)}. - * + * * @param position */ public void removeCheckState(int position) { @@ -2700,88 +2206,88 @@ public class DragSortListView extends ListView { } } - private static int buildRunList(SparseBooleanArray cip, int rangeStart, - int rangeEnd, int[] runStart, int[] runEnd) { - int runCount = 0; + /** + * Interface for customization of the floating View appearance + * and dragging behavior. Implement + * your own and pass it to {@link #setFloatViewManager}. If + * your own is not passed, the default {@link SimpleFloatViewManager} + * implementation is used. + */ + public interface FloatViewManager { + /** + * Return the floating View for item at position. + * DragSortListView will measure and layout this View for you, + * so feel free to just inflate it. You can help DSLV by + * setting some {@link ViewGroup.LayoutParams} on this View; + * otherwise it will set some for you (with a width of FILL_PARENT + * and a height of WRAP_CONTENT). + * + * @param position Position of item to drag (NOTE: + * position excludes header Views; thus, if you + * want to call {@link ListView#getChildAt(int)}, you will need + * to add {@link ListView#getHeaderViewsCount()} to the index). + * @return The View you wish to display as the floating View. + */ + View onCreateFloatView(int position); - int i = findFirstSetIndex(cip, rangeStart, rangeEnd); - if (i == -1) - return 0; + /** + * Called whenever the floating View is dragged. Float View + * properties can be changed here. Also, the upcoming location + * of the float View can be altered by setting + * location.x and location.y. + * + * @param floatView The floating View. + * @param location The location (top-left; relative to DSLV + * top-left) at which the float + * View would like to appear, given the current touch location + * and the offset provided in {@link DragSortListView#startDrag}. + * @param touch The current touch location (relative to DSLV + * top-left). + * @param pendingScroll + */ + void onDragFloatView(View floatView, Point location, Point touch); - int position = cip.keyAt(i); - int currentRunStart = position; - int currentRunEnd = currentRunStart + 1; - for (i++; i < cip.size() && (position = cip.keyAt(i)) < rangeEnd; i++) { - if (!cip.valueAt(i)) // not checked => not interesting - continue; - if (position == currentRunEnd) { - currentRunEnd++; - } else { - runStart[runCount] = currentRunStart; - runEnd[runCount] = currentRunEnd; - runCount++; - currentRunStart = position; - currentRunEnd = position + 1; - } - } - - if (currentRunEnd == rangeEnd) { - // rangeStart and rangeEnd are equivalent positions so to be - // consistent we translate them to the same integer value. That way - // we can check whether a run covers the entire range by just - // checking if the start equals the end position. - currentRunEnd = rangeStart; - } - runStart[runCount] = currentRunStart; - runEnd[runCount] = currentRunEnd; - runCount++; - - if (runCount > 1) { - if (runStart[0] == rangeStart && runEnd[runCount - 1] == rangeStart) { - // The last run ends at the end of the range, and the first run - // starts at the beginning of the range. So they are actually - // part of the same run, except they wrap around the end of the - // range. To avoid adjacent runs, we need to merge them. - runStart[0] = runStart[runCount - 1]; - runCount--; - } - } - return runCount; + /** + * Called when the float View is dropped; lets you perform + * any necessary cleanup. The internal DSLV floating View + * reference is set to null immediately after this is called. + * + * @param floatView The floating View passed to + * {@link #onCreateFloatView(int)}. + */ + void onDestroyFloatView(View floatView); } - private static int rotate(int value, int offset, int lowerBound, int upperBound) { - int windowSize = upperBound - lowerBound; + public interface DragListener { + void drag(int from, int to); - value += offset; - if (value < lowerBound) { - value += windowSize; - } else if (value >= upperBound) { - value -= windowSize; - } - return value; + void onItemHovered(int position); } - private static int findFirstSetIndex(SparseBooleanArray sba, int rangeStart, int rangeEnd) { - int size = sba.size(); - int i = insertionIndexForKey(sba, rangeStart); - while (i < size && sba.keyAt(i) < rangeEnd && !sba.valueAt(i)) - i++; - if (i == size || sba.keyAt(i) >= rangeEnd) - return -1; - return i; + /** + * Your implementation of this has to reorder your ListAdapter! + * Make sure to call + * {@link BaseAdapter#notifyDataSetChanged()} or something like it + * in your implementation. + * + * @author heycosmo + */ + public interface DropListener { + void drop(int from, int to); } - private static int insertionIndexForKey(SparseBooleanArray sba, int key) { - int low = 0; - int high = sba.size(); - while (high - low > 0) { - int middle = (low + high) >> 1; - if (sba.keyAt(middle) < key) - low = middle + 1; - else - high = middle; - } - return low; + /** + * Make sure to call + * {@link BaseAdapter#notifyDataSetChanged()} or something like it + * in your implementation. + * + * @author heycosmo + */ + public interface RemoveListener { + void remove(int which); + } + + public interface DragSortListener extends DropListener, DragListener, RemoveListener { } /** @@ -2789,40 +2295,456 @@ public class DragSortListView extends ListView { * scroll speed as a function of touch position and time. Use * {@link DragSortListView#setDragScrollProfile(DragScrollProfile)} to * set custom profile. - * - * @author heycosmo * + * @author heycosmo */ public interface DragScrollProfile { /** * Return a scroll speed in pixels/millisecond. Always return a * positive number. - * + * * @param w Normalized position in scroll region (i.e. w \in [0,1]). - * Small w typically means slow scrolling. + * Small w typically means slow scrolling. * @param t Time (in milliseconds) since start of scroll (handy if you - * want scroll acceleration). + * want scroll acceleration). * @return Scroll speed at position w and time t in pixels/ms. */ float getSpeed(float w, long t); } + private class AdapterWrapper extends BaseAdapter { + private final ListAdapter mAdapter; + + public AdapterWrapper(ListAdapter adapter) { + super(); + mAdapter = adapter; + + mAdapter.registerDataSetObserver(new DataSetObserver() { + public void onChanged() { + notifyDataSetChanged(); + } + + public void onInvalidated() { + notifyDataSetInvalidated(); + } + }); + } + + public ListAdapter getAdapter() { + return mAdapter; + } + + @Override + public long getItemId(int position) { + return mAdapter.getItemId(position); + } + + @Override + public Object getItem(int position) { + return mAdapter.getItem(position); + } + + @Override + public int getCount() { + return mAdapter.getCount(); + } + + @Override + public boolean areAllItemsEnabled() { + return mAdapter.areAllItemsEnabled(); + } + + @Override + public boolean isEnabled(int position) { + return mAdapter.isEnabled(position); + } + + @Override + public int getItemViewType(int position) { + return mAdapter.getItemViewType(position); + } + + @Override + public int getViewTypeCount() { + return mAdapter.getViewTypeCount(); + } + + @Override + public boolean hasStableIds() { + return mAdapter.hasStableIds(); + } + + @Override + public boolean isEmpty() { + return mAdapter.isEmpty(); + } + + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + + DragSortItemView v; + View child; + // Log.d("mobeta", + // "getView: position="+position+" convertView="+convertView); + if (convertView != null) { + v = (DragSortItemView) convertView; + View oldChild = v.getChildAt(0); + + child = mAdapter.getView(position, oldChild, DragSortListView.this); + if (child != oldChild) { + // shouldn't get here if user is reusing convertViews + // properly + if (oldChild != null) { + v.removeViewAt(0); + } + v.addView(child); + } + } else { + child = mAdapter.getView(position, null, DragSortListView.this); + if (child instanceof Checkable) { + v = new DragSortItemViewCheckable(getContext()); + } else { + v = new DragSortItemView(getContext()); + } + v.setLayoutParams(new AbsListView.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT)); + v.addView(child); + } + + // Set the correct item height given drag state; passed + // View needs to be measured if measurement is required. + adjustItem(position + getHeaderViewsCount(), v, true); + + return v; + } + } + + private class HeightCache { + + private final SparseIntArray mMap; + private final ArrayList mOrder; + private final int mMaxSize; + + public HeightCache(int size) { + mMap = new SparseIntArray(size); + mOrder = new ArrayList(size); + mMaxSize = size; + } + + /** + * Add item height at position if doesn't already exist. + */ + public void add(int position, int height) { + int currHeight = mMap.get(position, -1); + if (currHeight != height) { + if (currHeight == -1) { + if (mMap.size() == mMaxSize) { + // remove oldest entry + mMap.delete(mOrder.remove(0)); + } + } else { + // move position to newest slot + mOrder.remove((Integer) position); + } + mMap.put(position, height); + mOrder.add(position); + } + } + + public int get(int position) { + return mMap.get(position, -1); + } + + public void clear() { + mMap.clear(); + mOrder.clear(); + } + + } + + private class SmoothAnimator implements Runnable { + private final float mDurationF; + private final float mAlpha; + private final float mA; + private final float mB; + private final float mC; + private final float mD; + protected long mStartTime; + private boolean mCanceled; + + public SmoothAnimator(float smoothness, int duration) { + mAlpha = smoothness; + mDurationF = (float) duration; + mA = mD = 1f / (2f * mAlpha * (1f - mAlpha)); + mB = mAlpha / (2f * (mAlpha - 1f)); + mC = 1f / (1f - mAlpha); + } + + public float transform(float frac) { + if (frac < mAlpha) { + return mA * frac * frac; + } else if (frac < 1f - mAlpha) { + return mB + mC * frac; + } else { + return 1f - mD * (frac - 1f) * (frac - 1f); + } + } + + public void start() { + mStartTime = SystemClock.uptimeMillis(); + mCanceled = false; + onStart(); + post(this); + } + + public void cancel() { + mCanceled = true; + } + + public void onStart() { + // stub + } + + public void onUpdate(float frac, float smoothFrac) { + // stub + } + + public void onStop() { + // stub + } + + @Override + public void run() { + if (mCanceled) { + return; + } + + float fraction = ((float) (SystemClock.uptimeMillis() - mStartTime)) / mDurationF; + + if (fraction >= 1f) { + onUpdate(1f, 1f); + onStop(); + } else { + onUpdate(fraction, transform(fraction)); + post(this); + } + } + } + + /** + * Centers floating View under touch point. + */ + private class LiftAnimator extends SmoothAnimator { + + private float mInitDragDeltaY; + private float mFinalDragDeltaY; + + public LiftAnimator(float smoothness, int duration) { + super(smoothness, duration); + } + + @Override + public void onStart() { + mInitDragDeltaY = mDragDeltaY; + mFinalDragDeltaY = mFloatViewHeightHalf; + } + + @Override + public void onUpdate(float frac, float smoothFrac) { + if (mDragState != DRAGGING) { + cancel(); + } else { + mDragDeltaY = (int) (smoothFrac * mFinalDragDeltaY + (1f - smoothFrac) + * mInitDragDeltaY); + mFloatLoc.y = mY - mDragDeltaY; + doDragFloatView(true); + } + } + } + + /** + * Centers floating View over drop slot before destroying. + */ + private class DropAnimator extends SmoothAnimator { + + private int mDropPos; + private int srcPos; + private float mInitDeltaY; + private float mInitDeltaX; + + public DropAnimator(float smoothness, int duration) { + super(smoothness, duration); + } + + @Override + public void onStart() { + mDropPos = mFloatPos; + srcPos = mSrcPos; + mDragState = DROPPING; + mInitDeltaY = mFloatLoc.y - getTargetY(); + mInitDeltaX = mFloatLoc.x - getPaddingLeft(); + } + + private int getTargetY() { + final int first = getFirstVisiblePosition(); + final int otherAdjust = (mItemHeightCollapsed + getDividerHeight()) / 2; + View v = getChildAt(mDropPos - first); + int targetY = -1; + if (v != null) { + if (mDropPos == srcPos) { + targetY = v.getTop(); + } else if (mDropPos < srcPos) { + // expanded down + targetY = v.getTop() - otherAdjust; + } else { + // expanded up + targetY = v.getBottom() + otherAdjust - mFloatViewHeight; + } + } else { + // drop position is not on screen?? no animation + cancel(); + } + + return targetY; + } + + @Override + public void onUpdate(float frac, float smoothFrac) { + final int targetY = getTargetY(); + final int targetX = getPaddingLeft(); + final float deltaY = mFloatLoc.y - targetY; + final float deltaX = mFloatLoc.x - targetX; + final float f = 1f - smoothFrac; + if (f < Math.abs(deltaY / mInitDeltaY) || f < Math.abs(deltaX / mInitDeltaX)) { + mFloatLoc.y = targetY + (int) (mInitDeltaY * f); + mFloatLoc.x = getPaddingLeft() + (int) (mInitDeltaX * f); + doDragFloatView(true); + } + } + + @Override + public void onStop() { + dropFloatView(); + } + + } + + /** + * Collapses expanded items. + */ + private class RemoveAnimator extends SmoothAnimator { + + private float mFloatLocX; + private float mFirstStartBlank; + private float mSecondStartBlank; + + private int mFirstChildHeight = -1; + private int mSecondChildHeight = -1; + + private int mFirstPos; + private int mSecondPos; + private int srcPos; + + public RemoveAnimator(float smoothness, int duration) { + super(smoothness, duration); + } + + @Override + public void onStart() { + mFirstChildHeight = -1; + mSecondChildHeight = -1; + mFirstPos = mFirstExpPos; + mSecondPos = mSecondExpPos; + srcPos = mSrcPos; + mDragState = REMOVING; + + mFloatLocX = mFloatLoc.x; + if (mUseRemoveVelocity) { + float minVelocity = 2f * getWidth(); + if (mRemoveVelocityX == 0) { + mRemoveVelocityX = (mFloatLocX < 0 ? -1 : 1) * minVelocity; + } else { + minVelocity *= 2; + if (mRemoveVelocityX < 0 && mRemoveVelocityX > -minVelocity) + mRemoveVelocityX = -minVelocity; + else if (mRemoveVelocityX > 0 && mRemoveVelocityX < minVelocity) + mRemoveVelocityX = minVelocity; + } + } else { + destroyFloatView(); + } + } + + @Override + public void onUpdate(float frac, float smoothFrac) { + float f = 1f - smoothFrac; + + final int firstVis = getFirstVisiblePosition(); + View item = getChildAt(mFirstPos - firstVis); + ViewGroup.LayoutParams lp; + int blank; + + if (mUseRemoveVelocity) { + float dt = (float) (SystemClock.uptimeMillis() - mStartTime) / 1000; + if (dt == 0) + return; + float dx = mRemoveVelocityX * dt; + int w = getWidth(); + mRemoveVelocityX += (mRemoveVelocityX > 0 ? 1 : -1) * dt * w; + mFloatLocX += dx; + mFloatLoc.x = (int) mFloatLocX; + if (mFloatLocX < w && mFloatLocX > -w) { + mStartTime = SystemClock.uptimeMillis(); + doDragFloatView(true); + return; + } + } + + if (item != null) { + if (mFirstChildHeight == -1) { + mFirstChildHeight = getChildHeight(mFirstPos, item, false); + mFirstStartBlank = (float) (item.getHeight() - mFirstChildHeight); + } + blank = Math.max((int) (f * mFirstStartBlank), 1); + lp = item.getLayoutParams(); + lp.height = mFirstChildHeight + blank; + item.setLayoutParams(lp); + } + if (mSecondPos != mFirstPos) { + item = getChildAt(mSecondPos - firstVis); + if (item != null) { + if (mSecondChildHeight == -1) { + mSecondChildHeight = getChildHeight(mSecondPos, item, false); + mSecondStartBlank = (float) (item.getHeight() - mSecondChildHeight); + } + blank = Math.max((int) (f * mSecondStartBlank), 1); + lp = item.getLayoutParams(); + lp.height = mSecondChildHeight + blank; + item.setLayoutParams(lp); + } + } + } + + @Override + public void onStop() { + doRemoveItem(); + } + } + private class DragScroller implements Runnable { - private boolean mAbort; - - private long mPrevTime; - private long mCurrTime; - - private int dy; - private float dt; - private long tStart; - private int scrollDir; - public final static int STOP = -1; public final static int UP = 0; public final static int DOWN = 1; - + private boolean mAbort; + private long mPrevTime; + private long mCurrTime; + private int dy; + private float dt; + private long tStart; + private int scrollDir; private float mScrollSpeed; // pixels per ms private boolean mScrolling = false; @@ -2830,6 +2752,9 @@ public class DragSortListView extends ListView { private int mLastHeader; private int mFirstFooter; + public DragScroller() { + } + public boolean isScrolling() { return mScrolling; } @@ -2838,9 +2763,6 @@ public class DragSortListView extends ListView { return mScrolling ? scrollDir : STOP; } - public DragScroller() { - } - public void startScrolling(int dir) { if (!mScrolling) { // Debug.startMethodTracing("dslv-scroll"); @@ -2918,7 +2840,7 @@ public class DragSortListView extends ListView { // means user is scrolling up (list item moves down the screen, // remember // y=0 is at top of View). - dy = (int) Math.round(mScrollSpeed * dt); + dy = Math.round(mScrollSpeed * dt); int movePos; if (dy >= 0) { diff --git a/app/llx/app/src/main/java/com/mobeta/android/dslv/SimpleFloatViewManager.java b/app/llx/app/src/main/java/com/mobeta/android/dslv/SimpleFloatViewManager.java index 847e09d..53b8f88 100644 --- a/app/llx/app/src/main/java/com/mobeta/android/dslv/SimpleFloatViewManager.java +++ b/app/llx/app/src/main/java/com/mobeta/android/dslv/SimpleFloatViewManager.java @@ -14,14 +14,11 @@ import android.widget.ListView; */ public class SimpleFloatViewManager implements DragSortListView.FloatViewManager { + private final ListView mListView; private Bitmap mFloatBitmap; - private ImageView mImageView; - private int mFloatBGColor = Color.BLACK; - private ListView mListView; - public SimpleFloatViewManager(ListView lv) { mListView = lv; } diff --git a/app/llx/app/src/main/java/fr/xgouchet/texteditor/ui/AdvancedEditText.java b/app/llx/app/src/main/java/fr/xgouchet/texteditor/ui/AdvancedEditText.java index 5608eb4..ad071c8 100755 --- a/app/llx/app/src/main/java/fr/xgouchet/texteditor/ui/AdvancedEditText.java +++ b/app/llx/app/src/main/java/fr/xgouchet/texteditor/ui/AdvancedEditText.java @@ -31,40 +31,80 @@ import android.widget.Scroller; */ public class AdvancedEditText extends EditText implements OnKeyListener, OnGestureListener { - public interface OnAdvancedEditTextEvent { - public boolean onLeftEdgeSwipe(); - public boolean onTap(); - public void onPinchStart(); - public void onPinchZoom(double scale); - } - /** - * @param context - * the current context - * @param attrs - * some attributes - * @category ObjectLifecycle - */ - public AdvancedEditText(Context context, AttributeSet attrs) { - super(context, attrs); + /** + * The line numbers paint + */ + protected Paint mPaintNumbers; + /** + * The line numbers paint + */ + protected Paint mPaintHighlight; + /** + * the offset value in dp + */ + protected int mPaddingDP = 6; + /** + * the padding scaled + */ + protected int mPadding, mLinePadding; + /** + * the scale for desnity pixels + */ + protected float mScale; + protected float mScaledDensity; + /** + * the scroller instance + */ + protected Scroller mTedScroller; + /** + * the velocity tracker + */ + protected GestureDetector mGestureDetector; + /** + * the Max size of the view + */ + protected Point mMaxSize; + /** + * the highlighted line index + */ + protected int mHighlightedLine; + protected int mHighlightStart; + protected Rect mDrawingRect, mLineBounds; + protected boolean mFlingToScroll = true; + protected boolean mShowLineNumbers; + protected boolean mWordWrap; + protected OnAdvancedEditTextEvent mOnAdvancedEditTextEvent; + private int mDeferredScrollToLine = -1; + private double mInitialPinchDistance; + private int mFirstVisibleLine; + private boolean mSkipNextFling; - mPaintNumbers = new Paint(); - mPaintNumbers.setTypeface(Typeface.MONOSPACE); - mPaintNumbers.setAntiAlias(true); + /** + * @param context the current context + * @param attrs some attributes + * @category ObjectLifecycle + */ + public AdvancedEditText(Context context, AttributeSet attrs) { + super(context, attrs); - mPaintHighlight = new Paint(); + mPaintNumbers = new Paint(); + mPaintNumbers.setTypeface(Typeface.MONOSPACE); + mPaintNumbers.setAntiAlias(true); + + mPaintHighlight = new Paint(); DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); mScale = displayMetrics.density; - mScaledDensity = displayMetrics.scaledDensity; + mScaledDensity = displayMetrics.scaledDensity; - mPadding = (int) (mPaddingDP * mScale); + mPadding = (int) (mPaddingDP * mScale); - mHighlightedLine = mHighlightStart = -1; + mHighlightedLine = mHighlightStart = -1; - mDrawingRect = new Rect(); - mLineBounds = new Rect(); + mDrawingRect = new Rect(); + mLineBounds = new Rect(); - mGestureDetector = new GestureDetector(getContext(), this); + mGestureDetector = new GestureDetector(getContext(), this); mPaintHighlight.setColor(Color.BLACK); mPaintNumbers.setColor(Color.GRAY); @@ -74,153 +114,152 @@ public class AdvancedEditText extends EditText implements OnKeyListener, OnGestu setFlingToScroll(true); setWordWrap(true); setShowLineNumbers(true); - } + } @Override public void setTextSize(float size) { super.setTextSize(size); - mPaintNumbers.setTextSize((size>18 ? 18 : size)*mScaledDensity); - updateLinePadding(); + mPaintNumbers.setTextSize((size > 18 ? 18 : size) * mScaledDensity); + updateLinePadding(); } /** - * @see android.widget.TextView#computeScroll() - * @category View - */ - public void computeScroll() { + * @category View + * @see android.widget.TextView#computeScroll() + */ + public void computeScroll() { - if (mTedScroller != null) { - if (mTedScroller.computeScrollOffset()) { - scrollTo(mTedScroller.getCurrX(), mTedScroller.getCurrY()); - } - } else { - super.computeScroll(); - } - } + if (mTedScroller != null) { + if (mTedScroller.computeScrollOffset()) { + scrollTo(mTedScroller.getCurrX(), mTedScroller.getCurrY()); + } + } else { + super.computeScroll(); + } + } - private int mDeferredScrollToLine = -1; - public void scrollToLine(int line) { - Layout layout = getLayout(); - if(layout == null) { - mDeferredScrollToLine = line; - return; - } + public void scrollToLine(int line) { + Layout layout = getLayout(); + if (layout == null) { + mDeferredScrollToLine = line; + return; + } - int count = getLineCount(); - Rect r = new Rect(); + int count = getLineCount(); + Rect r = new Rect(); - int line_number = 1; - final String text = getText().toString(); - int offset = 0; - for (int i = 0; i < count; i++) { - if(line_number >= line) { - // need to set the selection now, otherwise the EditText will scroll back to the current selection, which is probably not at the same line - setSelection(layout.getLineStart(i)); - break; - } + int line_number = 1; + final String text = getText().toString(); + int offset = 0; + for (int i = 0; i < count; i++) { + if (line_number >= line) { + // need to set the selection now, otherwise the EditText will scroll back to the current selection, which is probably not at the same line + setSelection(layout.getLineStart(i)); + break; + } - getLineBounds(i, r); - offset = r.bottom; + getLineBounds(i, r); + offset = r.bottom; - boolean line_end = text.substring(layout.getLineStart(i), layout.getLineEnd(i)).indexOf('\n')!=-1; + boolean line_end = text.substring(layout.getLineStart(i), layout.getLineEnd(i)).indexOf('\n') != -1; - if(line_end) { - line_number++; - } - } + if (line_end) { + line_number++; + } + } - int max = layout.getLineBounds(count-1, null) - getHeight() - mPadding; - if(max < 0) max = 0; - if(offset > max) { - offset = max; - } + int max = layout.getLineBounds(count - 1, null) - getHeight() - mPadding; + if (max < 0) max = 0; + if (offset > max) { + offset = max; + } - offset -= getHeight()/2; - if(offset < 0) { - offset = 0; - } + offset -= getHeight() / 2; + if (offset < 0) { + offset = 0; + } - scrollTo(0, offset); - } + scrollTo(0, offset); + } - public int getSelectionLine() { - Layout layout = getLayout(); - if(layout == null) { - return 1; - } + public int getSelectionLine() { + Layout layout = getLayout(); + if (layout == null) { + return 1; + } - int count = getLineCount(); - int line_number = 1; - final String text = getText().toString(); - int selectionStart = getSelectionStart(); - for (int i = 0; i < count; i++) { - if(layout.getLineStart(i) <= selectionStart && layout.getLineEnd(i) > selectionStart) { - return line_number; - } + int count = getLineCount(); + int line_number = 1; + final String text = getText().toString(); + int selectionStart = getSelectionStart(); + for (int i = 0; i < count; i++) { + if (layout.getLineStart(i) <= selectionStart && layout.getLineEnd(i) > selectionStart) { + return line_number; + } - boolean line_end = text.substring(layout.getLineStart(i), layout.getLineEnd(i)).indexOf('\n')!=-1; + boolean line_end = text.substring(layout.getLineStart(i), layout.getLineEnd(i)).indexOf('\n') != -1; - if(line_end) { - line_number++; - } - } + if (line_end) { + line_number++; + } + } - return 1; - } + return 1; + } - /** - * @see android.widget.EditText#onDraw(android.graphics.Canvas) - * @category View - */ - public void onDraw(Canvas canvas) { + /** + * @category View + * @see android.widget.EditText#onDraw(android.graphics.Canvas) + */ + public void onDraw(Canvas canvas) { final Layout layout = getLayout(); - if(layout==null) { + if (layout == null) { super.onDraw(canvas); return; } - if(mDeferredScrollToLine != -1) { - final int l = mDeferredScrollToLine; - mDeferredScrollToLine = -1; - scrollToLine(l); - } + if (mDeferredScrollToLine != -1) { + final int l = mDeferredScrollToLine; + mDeferredScrollToLine = -1; + scrollToLine(l); + } - int count, lineX, baseline; + int count, lineX, baseline; - count = getLineCount(); + count = getLineCount(); - // get the drawing boundaries - getDrawingRect(mDrawingRect); + // get the drawing boundaries + getDrawingRect(mDrawingRect); - // display current line - computeLineHighlight(); + // display current line + computeLineHighlight(); - // draw line numbers - lineX = mDrawingRect.left + mLinePadding - mPadding; - int min = 0; - int max = count; - getLineBounds(0, mLineBounds); - int startBottom = mLineBounds.bottom; - int startTop = mLineBounds.top; - getLineBounds(count - 1, mLineBounds); - int endBottom = mLineBounds.bottom; - int endTop = mLineBounds.top; - if (count > 1 && endBottom > startBottom && endTop > startTop) { - min = Math.max(min, ((mDrawingRect.top - startBottom) * (count - 1)) / (endBottom - startBottom)); - max = Math.min(max, ((mDrawingRect.bottom - startTop) * (count - 1)) / (endTop - startTop) + 1); - } + // draw line numbers + lineX = mDrawingRect.left + mLinePadding - mPadding; + int min = 0; + int max = count; + getLineBounds(0, mLineBounds); + int startBottom = mLineBounds.bottom; + int startTop = mLineBounds.top; + getLineBounds(count - 1, mLineBounds); + int endBottom = mLineBounds.bottom; + int endTop = mLineBounds.top; + if (count > 1 && endBottom > startBottom && endTop > startTop) { + min = Math.max(min, ((mDrawingRect.top - startBottom) * (count - 1)) / (endBottom - startBottom)); + max = Math.min(max, ((mDrawingRect.bottom - startTop) * (count - 1)) / (endTop - startTop) + 1); + } int line_number = 1; - int first_visible_line = -1; + int first_visible_line = -1; boolean draw_line_number = true; final String text = getText().toString(); - for (int i = 0; i < max; i++) { - boolean line_end = text.substring(layout.getLineStart(i), layout.getLineEnd(i)).indexOf('\n')!=-1; - if(i >= min) { + for (int i = 0; i < max; i++) { + boolean line_end = text.substring(layout.getLineStart(i), layout.getLineEnd(i)).indexOf('\n') != -1; + if (i >= min) { baseline = getLineBounds(i, mLineBounds); - if(mLineBounds.top > mDrawingRect.bottom - mPadding) { - // over - break; - } + if (mLineBounds.top > mDrawingRect.bottom - mPadding) { + // over + break; + } if ((line_number - 1 == mHighlightedLine)) { canvas.drawRect(mLineBounds, mPaintHighlight); } @@ -230,62 +269,62 @@ public class AdvancedEditText extends EditText implements OnKeyListener, OnGestu } if (mShowLineNumbers && mLineBounds.bottom >= mDrawingRect.top + mPadding) { - if(first_visible_line == -1) { - first_visible_line = line_number; - mFirstVisibleLine = first_visible_line; - } + if (first_visible_line == -1) { + first_visible_line = line_number; + mFirstVisibleLine = first_visible_line; + } canvas.drawText(String.valueOf(line_number), mDrawingRect.left + mPadding, baseline, mPaintNumbers); } } } - if(line_end) { + if (line_end) { line_number++; } draw_line_number = line_end; - } + } if (mShowLineNumbers) { canvas.drawLine(lineX, mDrawingRect.top, lineX, mDrawingRect.bottom, mPaintNumbers); } - getLineBounds(count - 1, mLineBounds); - if (mMaxSize != null) { - mMaxSize.y = mLineBounds.bottom; - mMaxSize.x = Math.max(mMaxSize.x + mPadding - mDrawingRect.width(), 0); + getLineBounds(count - 1, mLineBounds); + if (mMaxSize != null) { + mMaxSize.y = mLineBounds.bottom; + mMaxSize.x = Math.max(mMaxSize.x + mPadding - mDrawingRect.width(), 0); mMaxSize.y = Math.max(mMaxSize.y + mPadding - mDrawingRect.height(), 0); - } + } - super.onDraw(canvas); - } + super.onDraw(canvas); + } - /** - * @see android.view.View.OnKeyListener#onKey(android.view.View, int, - * android.view.KeyEvent) - */ - public boolean onKey(View v, int keyCode, KeyEvent event) { - return false; - } + /** + * @see android.view.View.OnKeyListener#onKey(android.view.View, int, + * android.view.KeyEvent) + */ + public boolean onKey(View v, int keyCode, KeyEvent event) { + return false; + } - /** - * @see android.widget.TextView#onTouchEvent(android.view.MotionEvent) - * @category GestureDetection - */ - public boolean onTouchEvent(MotionEvent event) { - if(mTedScroller != null && !mTedScroller.isFinished()) { - mTedScroller.abortAnimation(); - } + /** + * @category GestureDetection + * @see android.widget.TextView#onTouchEvent(android.view.MotionEvent) + */ + public boolean onTouchEvent(MotionEvent event) { + if (mTedScroller != null && !mTedScroller.isFinished()) { + mTedScroller.abortAnimation(); + } - if (mGestureDetector != null) { - boolean res = mGestureDetector.onTouchEvent(event); - if(res) { + if (mGestureDetector != null) { + boolean res = mGestureDetector.onTouchEvent(event); + if (res) { MotionEvent cancel = MotionEvent.obtain(event); cancel.setAction(MotionEvent.ACTION_CANCEL); super.onTouchEvent(cancel); return true; } - } + } float dx = 0, dy = 0; boolean two_pointers = event.getPointerCount() == 2; @@ -310,93 +349,93 @@ public class AdvancedEditText extends EditText implements OnKeyListener, OnGestu } - return super.onTouchEvent(event); - } + return super.onTouchEvent(event); + } - /** - * @see android.view.GestureDetector.OnGestureListener#onDown(android.view.MotionEvent) - * @category GestureDetection - */ - public boolean onDown(MotionEvent e) { - return false; - } + /** + * @category GestureDetection + * @see android.view.GestureDetector.OnGestureListener#onDown(android.view.MotionEvent) + */ + public boolean onDown(MotionEvent e) { + return false; + } - /** - * @see android.view.GestureDetector.OnGestureListener#onSingleTapUp(android.view.MotionEvent) - * @category GestureDetection - */ - public boolean onSingleTapUp(MotionEvent e) { + /** + * @category GestureDetection + * @see android.view.GestureDetector.OnGestureListener#onSingleTapUp(android.view.MotionEvent) + */ + public boolean onSingleTapUp(MotionEvent e) { - if(mOnAdvancedEditTextEvent != null) { + if (mOnAdvancedEditTextEvent != null) { boolean res = mOnAdvancedEditTextEvent.onTap(); - if(res) { + if (res) { return true; } } - if (isEnabled()) { - ((InputMethodManager) getContext().getSystemService( - Context.INPUT_METHOD_SERVICE)).showSoftInput(this, - InputMethodManager.SHOW_IMPLICIT); - } + if (isEnabled()) { + ((InputMethodManager) getContext().getSystemService( + Context.INPUT_METHOD_SERVICE)).showSoftInput(this, + InputMethodManager.SHOW_IMPLICIT); + } return false; - } + } - /** - * @see android.view.GestureDetector.OnGestureListener#onShowPress(android.view.MotionEvent) - * @category GestureDetection - */ - public void onShowPress(MotionEvent e) { - } + /** + * @category GestureDetection + * @see android.view.GestureDetector.OnGestureListener#onShowPress(android.view.MotionEvent) + */ + public void onShowPress(MotionEvent e) { + } - /** - * @see android.view.GestureDetector.OnGestureListener#onLongPress(android.view.MotionEvent) - */ - public void onLongPress(MotionEvent e) { + /** + * @see android.view.GestureDetector.OnGestureListener#onLongPress(android.view.MotionEvent) + */ + public void onLongPress(MotionEvent e) { - } + } - /** - * @see android.view.GestureDetector.OnGestureListener#onScroll(android.view.MotionEvent, - * android.view.MotionEvent, float, float) - */ - public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, - float distanceY) { - // mTedScroller.setFriction(0); - if(e1.getX() < mLinePadding && mOnAdvancedEditTextEvent != null) { - mSkipNextFling = true; + /** + * @see android.view.GestureDetector.OnGestureListener#onScroll(android.view.MotionEvent, + * android.view.MotionEvent, float, float) + */ + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, + float distanceY) { + // mTedScroller.setFriction(0); + if (e1.getX() < mLinePadding && mOnAdvancedEditTextEvent != null) { + mSkipNextFling = true; return mOnAdvancedEditTextEvent.onLeftEdgeSwipe(); } - return false; - } + return false; + } - /** - * @see android.view.GestureDetector.OnGestureListener#onFling(android.view.MotionEvent, - * android.view.MotionEvent, float, float) - */ - public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, - float velocityY) { - if (!mFlingToScroll) { - return true; - } + /** + * @see android.view.GestureDetector.OnGestureListener#onFling(android.view.MotionEvent, + * android.view.MotionEvent, float, float) + */ + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, + float velocityY) { + if (!mFlingToScroll) { + return true; + } - if(mSkipNextFling) { - mSkipNextFling = false; - return true; - } + if (mSkipNextFling) { + mSkipNextFling = false; + return true; + } - if (mTedScroller != null) { - mTedScroller.fling(getScrollX(), getScrollY(), -(int) velocityX, - -(int) velocityY, 0, mMaxSize.x, 0, mMaxSize.y); - } - return true; - } + if (mTedScroller != null) { + mTedScroller.fling(getScrollX(), getScrollY(), -(int) velocityX, + -(int) velocityY, 0, mMaxSize.x, 0, mMaxSize.y); + } + return true; + } - /** - * Update view settings from the app preferences - * - * @category Custom - */ + /** + * Update view settings from the app preferences + * + * @category Custom + */ /*public void updateFromSettings() { if (isInEditMode()) { @@ -466,7 +505,6 @@ public class AdvancedEditText extends EditText implements OnKeyListener, OnGestu setPadding(mPadding, mPadding, mPadding, mPadding); } }*/ - public void setFlingToScroll(boolean flingToScroll) { if (flingToScroll) { mTedScroller = new Scroller(getContext()); @@ -482,17 +520,17 @@ public class AdvancedEditText extends EditText implements OnKeyListener, OnGestu updateLinePadding(); } - private void updateLinePadding() { - if (mShowLineNumbers) { - int max_text_size = (int) Math.ceil(mPaintNumbers.measureText("0000")); - mLinePadding = mPadding*3 + max_text_size; - } else { - mLinePadding = mPadding; - } - if(mLinePadding != getPaddingLeft()) { - setPadding(mLinePadding, mPadding, mPadding, mPadding); - } - } + private void updateLinePadding() { + if (mShowLineNumbers) { + int max_text_size = (int) Math.ceil(mPaintNumbers.measureText("0000")); + mLinePadding = mPadding * 3 + max_text_size; + } else { + mLinePadding = mPadding; + } + if (mLinePadding != getPaddingLeft()) { + setPadding(mLinePadding, mPadding, mPadding, mPadding); + } + } public void setWordWrap(boolean wordWrap) { mWordWrap = wordWrap; @@ -503,86 +541,60 @@ public class AdvancedEditText extends EditText implements OnKeyListener, OnGestu mOnAdvancedEditTextEvent = listener; } - /** - * Compute the line to highlight based on selection - */ - protected void computeLineHighlight() { - int i, line, selStart; - String text; + /** + * Compute the line to highlight based on selection + */ + protected void computeLineHighlight() { + int i, line, selStart; + String text; - if (!isEnabled()) { - mHighlightedLine = -1; - return; - } + if (!isEnabled()) { + mHighlightedLine = -1; + return; + } - selStart = getSelectionStart(); - if (mHighlightStart != selStart) { - text = getText().toString(); + selStart = getSelectionStart(); + if (mHighlightStart != selStart) { + text = getText().toString(); - line = i = 0; - while (i < selStart) { - i = text.indexOf("\n", i); - if (i < 0) { - break; - } - if (i < selStart) { - ++line; - } - ++i; - } + line = i = 0; + while (i < selStart) { + i = text.indexOf("\n", i); + if (i < 0) { + break; + } + if (i < selStart) { + ++line; + } + ++i; + } - mHighlightedLine = line; - } - } - - /** - * Like {@link EditText#getSelectionStart()} but returns the real start, even with a 'negative' selection. - */ - public int getTrueSelectionStart() { - return Math.min(super.getSelectionStart(), super.getSelectionEnd()); - } - - /** - * Like {@link EditText#getSelectionEnd()} but returns the real end, even with a 'negative' selection. - */ - public int getTrueSelectionEnd() { - return Math.max(super.getSelectionStart(), super.getSelectionEnd()); - } - - /** The line numbers paint */ - protected Paint mPaintNumbers; - /** The line numbers paint */ - protected Paint mPaintHighlight; - /** the offset value in dp */ - protected int mPaddingDP = 6; - /** the padding scaled */ - protected int mPadding, mLinePadding; - /** the scale for desnity pixels */ - protected float mScale; - protected float mScaledDensity; + mHighlightedLine = line; + } + } - /** the scroller instance */ - protected Scroller mTedScroller; - /** the velocity tracker */ - protected GestureDetector mGestureDetector; - /** the Max size of the view */ - protected Point mMaxSize; + /** + * Like {@link EditText#getSelectionStart()} but returns the real start, even with a 'negative' selection. + */ + public int getTrueSelectionStart() { + return Math.min(super.getSelectionStart(), super.getSelectionEnd()); + } - /** the highlighted line index */ - protected int mHighlightedLine; - protected int mHighlightStart; + /** + * Like {@link EditText#getSelectionEnd()} but returns the real end, even with a 'negative' selection. + */ + public int getTrueSelectionEnd() { + return Math.max(super.getSelectionStart(), super.getSelectionEnd()); + } - protected Rect mDrawingRect, mLineBounds; + public interface OnAdvancedEditTextEvent { + boolean onLeftEdgeSwipe(); - protected boolean mFlingToScroll = true; - protected boolean mShowLineNumbers; - protected boolean mWordWrap; + boolean onTap(); - private double mInitialPinchDistance; + void onPinchStart(); - protected OnAdvancedEditTextEvent mOnAdvancedEditTextEvent; - - private int mFirstVisibleLine; - private boolean mSkipNextFling; + void onPinchZoom(double scale); + } } diff --git a/app/llx/app/src/main/java/net/pierrox/lightning_launcher/LLAppPhone.java b/app/llx/app/src/main/java/net/pierrox/lightning_launcher/LLAppPhone.java index 25ea658..db5e6b3 100644 --- a/app/llx/app/src/main/java/net/pierrox/lightning_launcher/LLAppPhone.java +++ b/app/llx/app/src/main/java/net/pierrox/lightning_launcher/LLAppPhone.java @@ -27,7 +27,6 @@ package net.pierrox.lightning_launcher; import android.content.ComponentName; import android.content.Intent; import android.content.IntentFilter; -import android.os.Build; import android.view.View; import android.widget.Toast; @@ -103,7 +102,7 @@ public abstract class LLAppPhone extends LLApp { @Override public void unlockLockScreen(boolean restore_previous_task) { - if(LockScreen.sThis != null) { + if (LockScreen.sThis != null) { LockScreen.sThis.unlock(restore_previous_task); } else { Toast.makeText(this, net.pierrox.lightning_launcher_extreme.R.string.nly, Toast.LENGTH_SHORT).show(); @@ -133,7 +132,7 @@ public abstract class LLAppPhone extends LLApp { screen.pause(); } saveAllData(); - if(relaunch) { + if (relaunch) { Intent i = new Intent(this, Dashboard.class); i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(i); @@ -144,10 +143,8 @@ public abstract class LLAppPhone extends LLApp { @Override public boolean isLightningIntent(Intent intent) { ComponentName cn = intent.getComponent(); - if(cn != null) { - if(cn.getPackageName().equals(getPackageName()) && cn.getClassName().equals(Dashboard.class.getName())) { - return true; - } + if (cn != null) { + return cn.getPackageName().equals(getPackageName()) && cn.getClassName().equals(Dashboard.class.getName()); } return false; } @@ -156,7 +153,7 @@ public abstract class LLAppPhone extends LLApp { @Override public void displayPagerPage(int page, boolean reset_navigation_history) { Screen homeScreen = getScreen(ScreenIdentity.HOME); - if(homeScreen != null) { + if (homeScreen != null) { homeScreen.loadRootItemLayout(page, reset_navigation_history, true, true); } else { mAppEngine.writeCurrentPage(page); diff --git a/app/llx/app/src/main/java/net/pierrox/lightning_launcher/activities/AppDrawerX.java b/app/llx/app/src/main/java/net/pierrox/lightning_launcher/activities/AppDrawerX.java index 16b1c57..036519e 100644 --- a/app/llx/app/src/main/java/net/pierrox/lightning_launcher/activities/AppDrawerX.java +++ b/app/llx/app/src/main/java/net/pierrox/lightning_launcher/activities/AppDrawerX.java @@ -39,7 +39,6 @@ import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.AsyncTask; -import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.text.Editable; @@ -68,7 +67,6 @@ import net.pierrox.lightning_launcher.api.ScreenIdentity; import net.pierrox.lightning_launcher.configuration.GlobalConfig; import net.pierrox.lightning_launcher.configuration.ItemConfig; import net.pierrox.lightning_launcher.configuration.PageConfig; -import net.pierrox.lightning_launcher.data.State; import net.pierrox.lightning_launcher.configuration.SystemConfig; import net.pierrox.lightning_launcher.data.ContainerPath; import net.pierrox.lightning_launcher.data.EventAction; @@ -80,6 +78,7 @@ import net.pierrox.lightning_launcher.data.LightningIntent; import net.pierrox.lightning_launcher.data.Page; import net.pierrox.lightning_launcher.data.PageIndicator; import net.pierrox.lightning_launcher.data.Shortcut; +import net.pierrox.lightning_launcher.data.State; import net.pierrox.lightning_launcher.data.Utils; import net.pierrox.lightning_launcher.engine.LightningEngine; import net.pierrox.lightning_launcher.engine.Screen; @@ -106,33 +105,50 @@ import java.util.Stack; import java.util.StringTokenizer; public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeListener, TextView.OnEditorActionListener, TextWatcher { - public static final String INTENT_EXTRA_SELECT_FOR_ADD="s"; - public static final String INTENT_EXTRA_SEARCH="l"; + public static final String INTENT_EXTRA_SELECT_FOR_ADD = "s"; + public static final String INTENT_EXTRA_SEARCH = "l"; private static final int BUBBLE_MODE_DRAWER_MENU = 100; private static final int BUBBLE_MODE_DRAWER_MODE = 101; private static final int BUBBLE_MODE_DRAWER_VISIBILITY = 102; - private static final int DIALOG_MY_DRAWER=3; + private static final int DIALOG_MY_DRAWER = 3; - private static final int ACTION_BAR_HIDE_DELAY=2000; - private static final long ACTION_BAR_ANIM_IN_DURATION=300; - private static final long ACTION_BAR_ANIM_OUT_DURATION=500; + private static final int ACTION_BAR_HIDE_DELAY = 2000; + private static final long ACTION_BAR_ANIM_IN_DURATION = 300; + private static final long ACTION_BAR_ANIM_OUT_DURATION = 500; private static final int ACTION_BAR_CHILD_DRAWER_ACTIONS = 0; private static final int ACTION_BAR_CHILD_SEARCH = 1; private static final int ACTION_BAR_CHILD_BATCH = 2; - + private static final Matrix sIdentityTransform = new Matrix(); + private final Matrix mSavedItemLayoutLocalTransformCustom = new Matrix(); + private final Matrix mSavedItemLayoutLocalTransformByName = new Matrix(); private int mLayoutMode; - private boolean mSearchMode; private EditTextIme mSearchField; private ItemLayout mItemLayout; private ViewAnimator mActionBar; + private final SharedAsyncGraphicsDrawable.SharedAsyncGraphicsDrawableListener mActionBarSharedDrawableListener = new SharedAsyncGraphicsDrawable.SharedAsyncGraphicsDrawableListener() { + @Override + public void onSharedAsyncGraphicsDrawableInvalidated(SharedAsyncGraphicsDrawable drawable) { + mActionBar.invalidate(); + } + + @Override + public void onSharedAsyncGraphicsDrawableSizeChanged(SharedAsyncGraphicsDrawable drawable) { + mActionBar.requestLayout(); + } + }; + private final Runnable mHideCustomActionBarRunnable = new Runnable() { + @Override + public void run() { + hideCustomActionBar(); + } + }; private TextView mModeIcon; private TextView mBatchCount; private TextView mBatchAdd; - private Page mDrawerPage; private ArrayList mAllDrawerPageIDs; // gather ids of all pages displayed in the app drawer, including folders private State mState; @@ -146,120 +162,9 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi private boolean mBatchMode; private Drawable mActionBarBackground = null; private boolean mResumed; - - private static Matrix sIdentityTransform = new Matrix(); - private Matrix mSavedItemLayoutLocalTransformCustom = new Matrix(); - private Matrix mSavedItemLayoutLocalTransformByName = new Matrix(); - private ComponentName mThisCn; private ComponentName mDashboardCn; - private Animation mLayoutModeSwitchAnimation; - private int mNextLayoutMode; - - @Override - protected void createActivity(Bundle savedInstanceState) { - mThisCn = new ComponentName(this, AppDrawerX.class); - mDashboardCn = new ComponentName(this, Dashboard.class); - - if(mEngine.shouldDoFirstTimeInit() && !isSelectForAdd()) { - // redirect to home - startActivity(new Intent(this, Dashboard.class)); - finish(); - return; - } - - final Animation fadeIn = AnimationUtils.loadAnimation(AppDrawerX.this, android.R.anim.fade_in); - fadeIn.setInterpolator(this, android.R.anim.accelerate_interpolator); - long duration = fadeIn.getDuration()/4; // divided by 2 because there are two animations, then again by 2 to speed up things - fadeIn.setDuration(duration); - mLayoutModeSwitchAnimation = AnimationUtils.loadAnimation(this, android.R.anim.fade_out); - mLayoutModeSwitchAnimation.setInterpolator(this, android.R.anim.accelerate_interpolator); - mLayoutModeSwitchAnimation.setDuration(duration); - mLayoutModeSwitchAnimation.setAnimationListener(new Animation.AnimationListener() { - @Override - public void onAnimationStart(Animation animation) { - - } - - @Override - public void onAnimationEnd(Animation animation) { - setLayoutMode(mNextLayoutMode, false); - mItemLayout.startAnimation(fadeIn); - } - - @Override - public void onAnimationRepeat(Animation animation) { - - } - }); - - mNavigationStack=new Stack(); - - - Typeface typeface = LLApp.get().getIconsTypeface(); - - mModeIcon = (TextView)findViewById(R.id.drawer_mode_icon); - mModeIcon.setTypeface(typeface); - - mSearchField=(EditTextIme)findViewById(R.id.drawer_search_field); - mSearchField.setHint(getString(R.string.an_sa)); - mSearchField.setOnEditTextImeListener(this); - mSearchField.addTextChangedListener(this); - mSearchField.setOnEditorActionListener(this); - - final TextView batch_ok = (TextView) findViewById(R.id.batch_ok); - batch_ok.setTypeface(typeface); - batch_ok.setOnClickListener(this); - mBatchCount = (TextView) findViewById(R.id.batch_count); - mBatchCount.setOnClickListener(this); - mBatchAdd = (TextView) findViewById(R.id.batch_add); - mBatchAdd.setTypeface(typeface); - mBatchAdd.setOnClickListener(this); - - mItemLayout=(ItemLayout)findViewById(R.id.drawer_il); - mScreen.takeItemLayoutOwnership(mItemLayout); - - findViewById(R.id.drawer_mode_grp).setOnClickListener(this); - TextView btn; - - btn = (TextView) findViewById(R.id.drawer_zoom); - btn.setOnClickListener(this); - btn.setTypeface(typeface); - btn = (TextView) findViewById(R.id.drawer_search); - btn.setOnClickListener(this); - btn.setTypeface(typeface); - btn = (TextView) findViewById(R.id.drawer_more); - btn.setOnClickListener(this); - btn.setTypeface(typeface); - - mActionBar = (ViewAnimator) findViewById(R.id.ab); - - loadState(); - - mDrawerPage = mEngine.getOrLoadPage(Page.APP_DRAWER_PAGE); - - File items_file=mDrawerPage.getItemsFile(); - if(!items_file.exists() || mDrawerPage.items.size()==0) { - mLayoutMode = mState.layoutMode; - //firstTimeInit(); - refreshAppDrawerItems(false); - } else { - mLayoutMode = Utils.LAYOUT_MODE_UNDEFINED; - setLayoutMode(mState.layoutMode, false); - - if(getIntent().getBooleanExtra(INTENT_EXTRA_SEARCH, false)) { - mItemLayout.postDelayed(new Runnable() { - @Override - public void run() { - setSearchMode(true); - } - }, 300); - } else { - //checkIfRefreshIsNeeded(); - } - } - } /*private void checkIfRefreshIsNeeded() { final ArrayList items = new ArrayList(); @@ -285,6 +190,115 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi } }.execute((Void)null); }*/ + private int mNextLayoutMode; + + public static File getAppDrawerActionBarBackgroundFile(Page drawer_page) { + return new File(drawer_page.getIconDir(), FileUtils.SUFFIX_APP_DRAWER_AB_BACKGROUND); + } + + @Override + protected void createActivity(Bundle savedInstanceState) { + mThisCn = new ComponentName(this, AppDrawerX.class); + mDashboardCn = new ComponentName(this, Dashboard.class); + + if (mEngine.shouldDoFirstTimeInit() && !isSelectForAdd()) { + // redirect to home + startActivity(new Intent(this, Dashboard.class)); + finish(); + return; + } + + final Animation fadeIn = AnimationUtils.loadAnimation(AppDrawerX.this, android.R.anim.fade_in); + fadeIn.setInterpolator(this, android.R.anim.accelerate_interpolator); + long duration = fadeIn.getDuration() / 4; // divided by 2 because there are two animations, then again by 2 to speed up things + fadeIn.setDuration(duration); + mLayoutModeSwitchAnimation = AnimationUtils.loadAnimation(this, android.R.anim.fade_out); + mLayoutModeSwitchAnimation.setInterpolator(this, android.R.anim.accelerate_interpolator); + mLayoutModeSwitchAnimation.setDuration(duration); + mLayoutModeSwitchAnimation.setAnimationListener(new Animation.AnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + + } + + @Override + public void onAnimationEnd(Animation animation) { + setLayoutMode(mNextLayoutMode, false); + mItemLayout.startAnimation(fadeIn); + } + + @Override + public void onAnimationRepeat(Animation animation) { + + } + }); + + mNavigationStack = new Stack(); + + + Typeface typeface = LLApp.get().getIconsTypeface(); + + mModeIcon = findViewById(R.id.drawer_mode_icon); + mModeIcon.setTypeface(typeface); + + mSearchField = findViewById(R.id.drawer_search_field); + mSearchField.setHint(getString(R.string.an_sa)); + mSearchField.setOnEditTextImeListener(this); + mSearchField.addTextChangedListener(this); + mSearchField.setOnEditorActionListener(this); + + final TextView batch_ok = findViewById(R.id.batch_ok); + batch_ok.setTypeface(typeface); + batch_ok.setOnClickListener(this); + mBatchCount = findViewById(R.id.batch_count); + mBatchCount.setOnClickListener(this); + mBatchAdd = findViewById(R.id.batch_add); + mBatchAdd.setTypeface(typeface); + mBatchAdd.setOnClickListener(this); + + mItemLayout = findViewById(R.id.drawer_il); + mScreen.takeItemLayoutOwnership(mItemLayout); + + findViewById(R.id.drawer_mode_grp).setOnClickListener(this); + TextView btn; + + btn = findViewById(R.id.drawer_zoom); + btn.setOnClickListener(this); + btn.setTypeface(typeface); + btn = findViewById(R.id.drawer_search); + btn.setOnClickListener(this); + btn.setTypeface(typeface); + btn = findViewById(R.id.drawer_more); + btn.setOnClickListener(this); + btn.setTypeface(typeface); + + mActionBar = findViewById(R.id.ab); + + loadState(); + + mDrawerPage = mEngine.getOrLoadPage(Page.APP_DRAWER_PAGE); + + File items_file = mDrawerPage.getItemsFile(); + if (!items_file.exists() || mDrawerPage.items.size() == 0) { + mLayoutMode = mState.layoutMode; + //firstTimeInit(); + refreshAppDrawerItems(false); + } else { + mLayoutMode = Utils.LAYOUT_MODE_UNDEFINED; + setLayoutMode(mState.layoutMode, false); + + if (getIntent().getBooleanExtra(INTENT_EXTRA_SEARCH, false)) { + mItemLayout.postDelayed(new Runnable() { + @Override + public void run() { + setSearchMode(true); + } + }, 300); + } else { + //checkIfRefreshIsNeeded(); + } + } + } @Override protected void destroyActivity() { @@ -301,8 +315,8 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi super.onResume(); mResumed = true; - if(mActionBarBackground instanceof SharedAsyncGraphicsDrawable) { - ((SharedAsyncGraphicsDrawable)mActionBarBackground).resume(); + if (mActionBarBackground instanceof SharedAsyncGraphicsDrawable) { + ((SharedAsyncGraphicsDrawable) mActionBarBackground).resume(); } } @@ -311,8 +325,8 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi super.onPause(); mResumed = false; - if(mActionBarBackground instanceof SharedAsyncGraphicsDrawable) { - ((SharedAsyncGraphicsDrawable)mActionBarBackground).pause(); + if (mActionBarBackground instanceof SharedAsyncGraphicsDrawable) { + ((SharedAsyncGraphicsDrawable) mActionBarBackground).pause(); } setBatchMode(false); @@ -326,9 +340,9 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi protected Dialog onCreateDialog(int id) { AlertDialog.Builder builder; - switch(id) { + switch (id) { case DIALOG_MY_DRAWER: - builder=new AlertDialog.Builder(this); + builder = new AlertDialog.Builder(this); builder.setTitle(R.string.my_drawer_title); builder.setMessage(R.string.my_drawer_message); builder.setPositiveButton(android.R.string.ok, null); @@ -366,72 +380,6 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi return super.closeBubble(); } - @Override - protected void configureActivity(Page page) { - super.configureActivity(page); - - mActionBar.setVisibility(mDrawerPage.config.adHideActionBar || mIsAndroidActionBarDisplayed ? View.GONE : View.VISIBLE); - //noinspection ResourceType - ((FrameLayout.LayoutParams) mActionBar.getLayoutParams()).topMargin = mDrawerPage.config.statusBarHide ? 0 : mScreen.getSystemBarTintManager().getConfig().getStatusBarHeight(); - mActionBar.requestLayout(); - - int ab_text_color = mDrawerPage.config.adActionBarTextColor; - if(ab_text_color == 0) { - int[] attrs = {android.R.attr.textColor}; - TypedArray ta = obtainStyledAttributes(R.style.ab_text, attrs); - ab_text_color = ta.getColor(0, 0); - ta.recycle(); - } - int[] ids = new int[] { R.id.drawer_mode_icon, R.id.drawer_mode_value, R.id.drawer_zoom, R.id.drawer_search, R.id.drawer_more, R.id.drawer_search_field, R.id.batch_ok, R.id.batch_count, R.id.batch_add }; - for(int id : ids) { - ((TextView)mActionBar.findViewById(id)).setTextColor(ab_text_color); - } - int hint_color = Color.argb(Color.alpha(ab_text_color)/2, Color.red(ab_text_color), Color.green(ab_text_color), Color.blue(ab_text_color)); - mSearchField.setHintTextColor(hint_color); - - if(mActionBarBackground instanceof SharedAsyncGraphicsDrawable) { - ((SharedAsyncGraphicsDrawable) mActionBarBackground).unregisterListener(mActionBarSharedDrawableListener); - } - - mActionBarBackground = null; - File f = getAppDrawerActionBarBackgroundFile(page); - if(f.exists()) { - mActionBarBackground = Utils.loadDrawable(f); - } - - if(mActionBarBackground == null) { - int bg_res_id; - bg_res_id = R.color.color_primary; - mActionBarBackground = getResources().getDrawable(bg_res_id); - } - - if(mActionBarBackground instanceof SharedAsyncGraphicsDrawable) { - SharedAsyncGraphicsDrawable sd = (SharedAsyncGraphicsDrawable) mActionBarBackground; - sd.registerListener(mActionBarSharedDrawableListener); - if(mResumed) { - sd.resume(); - } - } - mActionBar.setBackgroundDrawable(mActionBarBackground); - } - - private SharedAsyncGraphicsDrawable.SharedAsyncGraphicsDrawableListener mActionBarSharedDrawableListener = new SharedAsyncGraphicsDrawable.SharedAsyncGraphicsDrawableListener() { - @Override - public void onSharedAsyncGraphicsDrawableInvalidated(SharedAsyncGraphicsDrawable drawable) { - mActionBar.invalidate(); - } - - @Override - public void onSharedAsyncGraphicsDrawableSizeChanged(SharedAsyncGraphicsDrawable drawable) { - mActionBar.requestLayout(); - } - }; - - @Override - protected int getActionBarHeight() { - return mDrawerPage.config.adHideActionBar || mIsAndroidActionBarDisplayed ? 0 : getResources().getDimensionPixelSize(R.dimen.ab_height); - } - // @Override // protected void myStartActivityForResult(Intent intent, int requestCode) { // realStartActivityForResult(intent, requestCode); @@ -442,9 +390,63 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi // myOnActivityResult(requestCode, resultCode, data); // } + @Override + protected void configureActivity(Page page) { + super.configureActivity(page); + + mActionBar.setVisibility(mDrawerPage.config.adHideActionBar || mIsAndroidActionBarDisplayed ? View.GONE : View.VISIBLE); + //noinspection ResourceType + ((FrameLayout.LayoutParams) mActionBar.getLayoutParams()).topMargin = mDrawerPage.config.statusBarHide ? 0 : mScreen.getSystemBarTintManager().getConfig().getStatusBarHeight(); + mActionBar.requestLayout(); + + int ab_text_color = mDrawerPage.config.adActionBarTextColor; + if (ab_text_color == 0) { + int[] attrs = {android.R.attr.textColor}; + TypedArray ta = obtainStyledAttributes(R.style.ab_text, attrs); + ab_text_color = ta.getColor(0, 0); + ta.recycle(); + } + int[] ids = new int[]{R.id.drawer_mode_icon, R.id.drawer_mode_value, R.id.drawer_zoom, R.id.drawer_search, R.id.drawer_more, R.id.drawer_search_field, R.id.batch_ok, R.id.batch_count, R.id.batch_add}; + for (int id : ids) { + ((TextView) mActionBar.findViewById(id)).setTextColor(ab_text_color); + } + int hint_color = Color.argb(Color.alpha(ab_text_color) / 2, Color.red(ab_text_color), Color.green(ab_text_color), Color.blue(ab_text_color)); + mSearchField.setHintTextColor(hint_color); + + if (mActionBarBackground instanceof SharedAsyncGraphicsDrawable) { + ((SharedAsyncGraphicsDrawable) mActionBarBackground).unregisterListener(mActionBarSharedDrawableListener); + } + + mActionBarBackground = null; + File f = getAppDrawerActionBarBackgroundFile(page); + if (f.exists()) { + mActionBarBackground = Utils.loadDrawable(f); + } + + if (mActionBarBackground == null) { + int bg_res_id; + bg_res_id = R.color.color_primary; + mActionBarBackground = getResources().getDrawable(bg_res_id); + } + + if (mActionBarBackground instanceof SharedAsyncGraphicsDrawable) { + SharedAsyncGraphicsDrawable sd = (SharedAsyncGraphicsDrawable) mActionBarBackground; + sd.registerListener(mActionBarSharedDrawableListener); + if (mResumed) { + sd.resume(); + } + } + mActionBar.setBackgroundDrawable(mActionBarBackground); + } + + @Override + protected int getActionBarHeight() { + return mDrawerPage.config.adHideActionBar || mIsAndroidActionBarDisplayed ? 0 : getResources().getDimensionPixelSize(R.dimen.ab_height); + } + @Override protected boolean goBack() { - if(mActionBar.getDisplayedChild() == ACTION_BAR_CHILD_BATCH) { + if (mActionBar.getDisplayedChild() == ACTION_BAR_CHILD_BATCH) { doAddForBatchMode(); } else { FolderView fv = mScreen.findTopmostFolderView(); @@ -452,7 +454,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi mScreen.closeFolder(fv, true); return true; } else { - if(!mScreen.zoomToOrigin(mScreen.getTargetOrTopmostItemLayout())) { + if (!mScreen.zoomToOrigin(mScreen.getTargetOrTopmostItemLayout())) { finish(); } } @@ -460,10 +462,6 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi return false; } - public static File getAppDrawerActionBarBackgroundFile(Page drawer_page) { - return new File(drawer_page.getIconDir(), FileUtils.SUFFIX_APP_DRAWER_AB_BACKGROUND); - } - private boolean isSelectForAdd() { return getIntent().hasExtra(INTENT_EXTRA_SELECT_FOR_ADD); } @@ -474,40 +472,40 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi private void loadState() { File state_file = FileUtils.getStateFile(mEngine.getBaseDir()); - JSONObject json=FileUtils.readJSONObjectFromFile(state_file); - if(json==null) { - json=new JSONObject(); + JSONObject json = FileUtils.readJSONObjectFromFile(state_file); + if (json == null) { + json = new JSONObject(); } mState = new State(); mState.loadFieldsFromJSONObject(json, null); - if(mState.layoutTransformCustomS!=null) { + if (mState.layoutTransformCustomS != null) { boolean error = false; StringTokenizer st = new StringTokenizer(mState.layoutTransformCustomS); float[] values = new float[9]; - for(int i=0; i<9; i++) { + for (int i = 0; i < 9; i++) { values[i] = Float.parseFloat(st.nextToken()); - if(Float.isNaN(values[i])) { + if (Float.isNaN(values[i])) { error = true; } } - if(!error) { + if (!error) { mSavedItemLayoutLocalTransformCustom.setValues(values); } } - if(mState.layoutTransformByNameS!=null) { + if (mState.layoutTransformByNameS != null) { boolean error = false; StringTokenizer st = new StringTokenizer(mState.layoutTransformByNameS); float[] values = new float[9]; - for(int i=0; i<9; i++) { + for (int i = 0; i < 9; i++) { values[i] = Float.parseFloat(st.nextToken()); - if(Float.isNaN(values[i])) { + if (Float.isNaN(values[i])) { error = true; } } - if(!error) { + if (!error) { mSavedItemLayoutLocalTransformByName.setValues(values); } } @@ -515,35 +513,35 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi private void saveState() { try { - if(mLayoutMode == Utils.LAYOUT_MODE_CUSTOM) { + if (mLayoutMode == Utils.LAYOUT_MODE_CUSTOM) { mSavedItemLayoutLocalTransformCustom.set(mItemLayout.getLocalTransform()); - } else if(mLayoutMode == Utils.LAYOUT_MODE_BY_NAME) { + } else if (mLayoutMode == Utils.LAYOUT_MODE_BY_NAME) { mSavedItemLayoutLocalTransformByName.set(mItemLayout.getLocalTransform()); } float[] values = new float[9]; mSavedItemLayoutLocalTransformCustom.getValues(values); mState.layoutTransformCustomS = String.valueOf(values[0]); - for(int i=1; i<9; i++) { - mState.layoutTransformCustomS += " "+values[i]; + for (int i = 1; i < 9; i++) { + mState.layoutTransformCustomS += " " + values[i]; } mSavedItemLayoutLocalTransformByName.getValues(values); mState.layoutTransformByNameS = String.valueOf(values[0]); - for(int i=1; i<9; i++) { - mState.layoutTransformByNameS += " "+values[i]; + for (int i = 1; i < 9; i++) { + mState.layoutTransformByNameS += " " + values[i]; } JSONObject json = JsonLoader.toJSONObject(mState, new State()); File out = FileUtils.getStateFile(mEngine.getBaseDir()); FileUtils.saveStringToFile(json.toString(), out); - } catch(Exception e) { + } catch (Exception e) { // pass } } private void setLayoutModeAnimated(int mode) { - if(mLayoutMode != mode) { + if (mLayoutMode != mode) { mNextLayoutMode = mode; mLayoutModeSwitchAnimation.cancel(); mItemLayout.startAnimation(mLayoutModeSwitchAnimation); @@ -555,17 +553,17 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi } private void setLayoutMode(int mode, boolean refresh, boolean force) { - if(!force && !hasMode(mode)) { + if (!force && !hasMode(mode)) { mode = findNextAvailableMode(mode); } - if(mode==mLayoutMode && !refresh) return; + if (mode == mLayoutMode && !refresh) return; - if(mBatchMode) { + if (mBatchMode) { setBatchMode(false); } - if(mLayoutMode!= Utils.LAYOUT_MODE_UNDEFINED && !refresh) { + if (mLayoutMode != Utils.LAYOUT_MODE_UNDEFINED && !refresh) { mScreen.closeAllFolders(false); // when switching layouts the folder opener item view is destroyed, so remove folders too @@ -581,11 +579,11 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi mAllDrawerPageIDs = new ArrayList<>(); - switch(mode) { + switch (mode) { case Utils.LAYOUT_MODE_CUSTOM: mAllDrawerPageIDs.add(mDrawerPage.id); items = new ArrayList(mDrawerPage.items); - for(Item i : items) { + for (Item i : items) { i.setCellT(null); } honour_pinned_items = mSystemConfig.hasSwitch(SystemConfig.SWITCH_HONOUR_PINNED_ITEMS); @@ -600,18 +598,18 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi case Utils.LAYOUT_MODE_FREQUENTLY_USED: items = new ArrayList(); addAppsFromPage(mDrawerPage, items, mAllDrawerPageIDs); - for(Item i : items) { - if(i instanceof Shortcut) { - Shortcut s = (Shortcut)i; - ComponentName cn=s.getIntent().getComponent(); - if(mThisCn.compareTo(cn) != 0) { + for (Item i : items) { + if (i instanceof Shortcut) { + Shortcut s = (Shortcut) i; + ComponentName cn = s.getIntent().getComponent(); + if (mThisCn.compareTo(cn) != 0) { s.mLaunchCount = s.getPage().getEngine().getShortcutLaunchCount(s); } } } - for(int i=items.size()-1; i>=0; i--) { + for (int i = items.size() - 1; i >= 0; i--) { final Item item = items.get(i); - if(item instanceof Shortcut && item.mLaunchCount==0) items.remove(i); + if (item instanceof Shortcut && item.mLaunchCount == 0) items.remove(i); } Collections.sort(items, Utils.sItemComparatorByLaunchCount); break; @@ -622,19 +620,19 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi addAppsFromPage(mDrawerPage, all_items, mAllDrawerPageIDs); am = (ActivityManager) getSystemService(ACTIVITY_SERVICE); List recent = am.getRecentTasks(25, ActivityManager.RECENT_IGNORE_UNAVAILABLE); - for(ActivityManager.RecentTaskInfo info : recent) { + for (ActivityManager.RecentTaskInfo info : recent) { ComponentName cn = info.baseIntent.getComponent(); - if(cn != null && cn.compareTo(mThisCn) != 0) { + if (cn != null && cn.compareTo(mThisCn) != 0) { String pkg = cn.getPackageName(); String cls = cn.getClassName(); Item i = findItemByComponent(all_items, pkg, cls); - if(i!=null && findItemByComponent(items, pkg, cls)==null) { + if (i != null && findItemByComponent(items, pkg, cls) == null) { items.add(i); } } } - for(Item i : all_items) { - if(!(i instanceof Shortcut)) { + for (Item i : all_items) { + if (!(i instanceof Shortcut)) { items.add(i); } } @@ -653,14 +651,14 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi am = (ActivityManager) getSystemService(ACTIVITY_SERVICE); // pm = getPackageManager(); List running = am.getRunningAppProcesses(); - for(ActivityManager.RunningAppProcessInfo info : running) { + for (ActivityManager.RunningAppProcessInfo info : running) { // if(info.importance==ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY) continue; // if(info.importance==ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE) continue; // if(info.importance==ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) continue; - for(String pkg : info.pkgList) { + for (String pkg : info.pkgList) { Item i = findItemByComponent(all_items, pkg, null); - if(i!=null && findItemByComponent(items, pkg, null)==null) { + if (i != null && findItemByComponent(items, pkg, null) == null) { items.add(i); } @@ -700,8 +698,8 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi // items.add(i); // } // } - for(Item i : all_items) { - if(!(i instanceof Shortcut)) { + for (Item i : all_items) { + if (!(i instanceof Shortcut)) { items.add(i); } } @@ -713,7 +711,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi mItemLayout.cancelFling(); Page p; - if(mode == Utils.LAYOUT_MODE_CUSTOM) { + if (mode == Utils.LAYOUT_MODE_CUSTOM) { p = mDrawerPage; } else { p = new MergedPage(mDrawerPage.getEngine(), mDrawerPage.config, items); @@ -721,60 +719,60 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi mItemLayout.setAllowMergeViews(!refresh); mItemLayout.setPage(p); mItemLayout.setHonourPinnedItems(honour_pinned_items); - for(Item i : items) { + for (Item i : items) { mItemLayout.getItemView(i).setAlwaysPinnedAndVisible(!(i instanceof Shortcut)); } - if(mode!= Utils.LAYOUT_MODE_CUSTOM) { + if (mode != Utils.LAYOUT_MODE_CUSTOM) { layoutItemsInTable(true); } String icon_text = ""; int label_res_id = 0; - switch(mode) { + switch (mode) { case Utils.LAYOUT_MODE_BY_NAME: icon_text = "W"; - label_res_id=R.string.mi_mode_by_name; + label_res_id = R.string.mi_mode_by_name; break; case Utils.LAYOUT_MODE_CUSTOM: icon_text = "V"; - label_res_id=R.string.mi_mode_custom; + label_res_id = R.string.mi_mode_custom; break; case Utils.LAYOUT_MODE_FREQUENTLY_USED: icon_text = "R"; - label_res_id=R.string.mi_mode_frequently_used; + label_res_id = R.string.mi_mode_frequently_used; break; case Utils.LAYOUT_MODE_RECENT_APPS: icon_text = "Q"; - label_res_id=R.string.mi_mode_recent_apps; + label_res_id = R.string.mi_mode_recent_apps; break; case Utils.LAYOUT_MODE_RECENTLY_UPDATED: icon_text = "T"; - label_res_id=R.string.mi_mode_recently_updated; + label_res_id = R.string.mi_mode_recently_updated; break; case Utils.LAYOUT_MODE_RUNNING: icon_text = "S"; - label_res_id=R.string.mi_mode_running; + label_res_id = R.string.mi_mode_running; break; } mModeIcon.setText(icon_text); - ((TextView)findViewById(R.id.drawer_mode_value)).setText(label_res_id); + ((TextView) findViewById(R.id.drawer_mode_value)).setText(label_res_id); - if(!refresh) { - if(mLayoutMode == Utils.LAYOUT_MODE_CUSTOM) { + if (!refresh) { + if (mLayoutMode == Utils.LAYOUT_MODE_CUSTOM) { mSavedItemLayoutLocalTransformCustom.set(mItemLayout.getLocalTransform()); - } else if(mLayoutMode == Utils.LAYOUT_MODE_BY_NAME) { + } else if (mLayoutMode == Utils.LAYOUT_MODE_BY_NAME) { mSavedItemLayoutLocalTransformByName.set(mItemLayout.getLocalTransform()); } - if(mode == Utils.LAYOUT_MODE_CUSTOM) { + if (mode == Utils.LAYOUT_MODE_CUSTOM) { mItemLayout.setLocalTransform(mSavedItemLayoutLocalTransformCustom); - } else if(mode == Utils.LAYOUT_MODE_BY_NAME) { + } else if (mode == Utils.LAYOUT_MODE_BY_NAME) { mItemLayout.setLocalTransform(mSavedItemLayoutLocalTransformByName); } else { mItemLayout.setLocalTransform(sIdentityTransform); @@ -790,13 +788,13 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi } private int findNextAvailableMode(int start_mode) { - for(int m=start_mode+1; m<=Utils.LAYOUT_MODE_LAST; m++) { - if(hasMode(m)) { + for (int m = start_mode + 1; m <= Utils.LAYOUT_MODE_LAST; m++) { + if (hasMode(m)) { return m; } } - for(int m=0; m<=start_mode; m++) { - if(hasMode(m)) { + for (int m = 0; m <= start_mode; m++) { + if (hasMode(m)) { return m; } } @@ -805,13 +803,13 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi } private int findPreviousAvailableMode(int start_mode) { - for(int m=start_mode-1; m>=0; m--) { - if(hasMode(m)) { + for (int m = start_mode - 1; m >= 0; m--) { + if (hasMode(m)) { return m; } } - for(int m=Utils.LAYOUT_MODE_LAST; m>=start_mode; m--) { - if(hasMode(m)) { + for (int m = Utils.LAYOUT_MODE_LAST; m >= start_mode; m--) { + if (hasMode(m)) { return m; } } @@ -828,12 +826,12 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi } private void addAppsFromPage(Page page, ArrayList items, ArrayList allPageIds) { - if(allPageIds != null) { + if (allPageIds != null) { allPageIds.add(page.id); } - for(Item i : page.items) { - if(i.getClass()==Folder.class) { - addAppsFromPage(((Folder)i).getOrLoadFolderPage(), items, allPageIds); + for (Item i : page.items) { + if (i.getClass() == Folder.class) { + addAppsFromPage(((Folder) i).getOrLoadFolderPage(), items, allPageIds); } else { items.add(i); } @@ -842,14 +840,14 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi private void gatherCheckedItems(Page page, ArrayList items) { ItemLayout[] ils = mScreen.getItemLayoutsForPage(page.id); - if(ils.length == 0) { + if (ils.length == 0) { // view not built, nothing to do return; } ItemLayout il = ils[0]; - for(Item i : page.items) { + for (Item i : page.items) { ItemView itemView = il.getItemView(i); - if(itemView != null) { + if (itemView != null) { // in alphabetical mode for instance, folders are not displayed and don't have views boolean checked = itemView.isChecked(); if (i.getClass() == Folder.class) { @@ -869,14 +867,14 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi } private Item findItemByComponent(ArrayList items, String pkg, String cls) { - for(Item i : items) { - if(i.getClass()==Shortcut.class) { - ComponentName cn = ((Shortcut)i).getIntent().getComponent(); - if(cn.getPackageName().equals(pkg)) { - if(cls==null) { + for (Item i : items) { + if (i.getClass() == Shortcut.class) { + ComponentName cn = ((Shortcut) i).getIntent().getComponent(); + if (cn.getPackageName().equals(pkg)) { + if (cls == null) { return i; } else { - if(cn.getClassName().equals(cls)) { + if (cn.getClassName().equals(cls)) { return i; } } @@ -890,11 +888,11 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi private void layoutItemsInTable(boolean full_layout) { ItemLayout il = mItemLayout; Page page = il.getPage(); - boolean horizontal = page.config.scrollingDirection==PageConfig.ScrollingDirection.X; + boolean horizontal = page.config.scrollingDirection == PageConfig.ScrollingDirection.X; final int width = il.getWidth(); final int height = il.getHeight(); - if(width==0 || height==0) { + if (width == 0 || height == 0) { // for(Item i : page.items) { // if (!(i instanceof Shortcut)) continue; // if (mItemLayout.getItemView(i).isViewVisible()) { @@ -904,38 +902,38 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi return; } - int x_max=(int) (width /(il.getCurrentScale()*il.getCellWidth())); - if(x_max<1) x_max=1; - if(x_max>40) x_max=40; - int y_max=(int) (height /(il.getCurrentScale()*il.getCellHeight())); - if(y_max<1) y_max=1; + int x_max = (int) (width / (il.getCurrentScale() * il.getCellWidth())); + if (x_max < 1) x_max = 1; + if (x_max > 40) x_max = 40; + int y_max = (int) (height / (il.getCurrentScale() * il.getCellHeight())); + if (y_max < 1) y_max = 1; - int x=0, y=0, px=0; + int x = 0, y = 0, px = 0; - mVisibleItemsCount=0; + mVisibleItemsCount = 0; - for(Item i : page.items) { - if(!(i instanceof Shortcut)) continue; - if(mItemLayout.getItemView(i).isViewVisible()) { - i.setCellT(new Rect(x, y, x+1, y+1)); + for (Item i : page.items) { + if (!(i instanceof Shortcut)) continue; + if (mItemLayout.getItemView(i).isViewVisible()) { + i.setCellT(new Rect(x, y, x + 1, y + 1)); - if(horizontal) { + if (horizontal) { px++; x++; - if(px==x_max) { - px=0; - x-=x_max; + if (px == x_max) { + px = 0; + x -= x_max; y++; - if(y==y_max) { - y=0; - x+=x_max; + if (y == y_max) { + y = 0; + x += x_max; } } } else { x++; - if(x==x_max) { - x=0; + if (x == x_max) { + x = 0; y++; } } @@ -943,7 +941,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi mVisibleItemsCount++; } - if(full_layout) { + if (full_layout) { il.requestLayout(); } else { il.reLayoutItems(); @@ -952,12 +950,12 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi @SuppressLint("DefaultLocale") private void filterApps(String filter) { - ArrayList items=mItemLayout.getPage().items; - if(filter!=null) { - final String filter_l=filter.toLowerCase(); + ArrayList items = mItemLayout.getPage().items; + if (filter != null) { + final String filter_l = filter.toLowerCase(); boolean empty = filter.equals(""); - for(Item i : items) { - if(i instanceof Shortcut) { + for (Item i : items) { + if (i instanceof Shortcut) { Shortcut s = (Shortcut) i; boolean match = !empty && s.getLabel().toLowerCase().contains(filter_l); s.setVisible(match); @@ -967,17 +965,17 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi i.setVisible(false); } } - if(mActionBar.getDisplayedChild() == ACTION_BAR_CHILD_SEARCH) { + if (mActionBar.getDisplayedChild() == ACTION_BAR_CHILD_SEARCH) { Collections.sort(items, new Comparator() { @Override public int compare(Item item1, Item item2) { - String s1 = item1 instanceof Shortcut ? ((Shortcut)item1).getLabel().toLowerCase() : ""; - String s2 = item2 instanceof Shortcut ? ((Shortcut)item2).getLabel().toLowerCase() : ""; + String s1 = item1 instanceof Shortcut ? ((Shortcut) item1).getLabel().toLowerCase() : ""; + String s2 = item2 instanceof Shortcut ? ((Shortcut) item2).getLabel().toLowerCase() : ""; boolean s1_start = s1.startsWith(filter_l); boolean s2_start = s2.startsWith(filter_l); - if(s1_start && !s2_start) { + if (s1_start && !s2_start) { return -1; - } else if(!s1_start && s2_start) { + } else if (!s1_start && s2_start) { return 1; } else { return Utils.sItemNameCollator.compare(s1, s2); @@ -986,16 +984,16 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi }); } } else { - for(Item i : items) { + for (Item i : items) { i.setVisible(true); - if(i instanceof Shortcut) { + if (i instanceof Shortcut) { ShortcutView shortcutView = (ShortcutView) mItemLayout.getItemView(i); shortcutView.highlightText(null); } } Collections.sort(items, Utils.sItemComparatorByNameAsc); } - if(mLayoutMode== Utils.LAYOUT_MODE_CUSTOM) { + if (mLayoutMode == Utils.LAYOUT_MODE_CUSTOM) { mItemLayout.computeBoundingBox(mItemLayout.getWidth(), mItemLayout.getHeight()); mItemLayout.animateZoomTo(ItemLayout.POSITION_FULL_SCALE, 1); } else { @@ -1006,28 +1004,28 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi private void setSearchMode(boolean on) { final int displayedChild = mActionBar.getDisplayedChild(); - if(on && displayedChild == ACTION_BAR_CHILD_SEARCH) return; - if(!on && displayedChild != ACTION_BAR_CHILD_SEARCH) return; + if (on && displayedChild == ACTION_BAR_CHILD_SEARCH) return; + if (!on && displayedChild != ACTION_BAR_CHILD_SEARCH) return; mActionBar.setDisplayedChild(on ? ACTION_BAR_CHILD_SEARCH : ACTION_BAR_CHILD_DRAWER_ACTIONS); - InputMethodManager imm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE); - if(mSearchFocusedItemView != null) { + InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); + if (mSearchFocusedItemView != null) { mSearchFocusedItemView.setFocused(false); } filterApps(null); - final ItemLayout il=mItemLayout; - if(on) { - if(mEditMode) leaveEditMode(); + final ItemLayout il = mItemLayout; + if (on) { + if (mEditMode) leaveEditMode(); closeBubble(); - mLayoutModeBeforeSearch=mLayoutMode; - if(mLayoutMode != Utils.LAYOUT_MODE_BY_NAME) { + mLayoutModeBeforeSearch = mLayoutMode; + if (mLayoutMode != Utils.LAYOUT_MODE_BY_NAME) { setLayoutMode(Utils.LAYOUT_MODE_BY_NAME, false, true); } mSearchField.setText(""); mSearchField.requestFocus(); int w = il.getWidth(); int h = il.getHeight(); - if(w != 0 && h != 0) { + if (w != 0 && h != 0) { il.setLayoutParams(new FrameLayout.LayoutParams(w, h)); } imm.showSoftInput(mSearchField, 0); @@ -1041,7 +1039,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi mSearchMode = true; } else { imm.hideSoftInputFromWindow(mSearchField.getWindowToken(), 0); - if(mLayoutModeBeforeSearch != mLayoutMode) { + if (mLayoutModeBeforeSearch != mLayoutMode) { setLayoutMode(mLayoutModeBeforeSearch, false); } il.animateZoomTo(ItemLayout.POSITION_ORIGIN, 1); @@ -1051,7 +1049,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi il.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); } }, 1000); - if(mDrawerPage.config.adHideActionBar) { + if (mDrawerPage.config.adHideActionBar) { hideCustomActionBar(); } mScreen.hideStatusBarIfNeeded(); @@ -1062,32 +1060,32 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi private void setBatchMode(boolean on) { mBatchMode = on; final int displayedChild = mActionBar.getDisplayedChild(); - if(on && displayedChild == ACTION_BAR_CHILD_BATCH) return; - if(!on && displayedChild != ACTION_BAR_CHILD_BATCH) return; + if (on && displayedChild == ACTION_BAR_CHILD_BATCH) return; + if (!on && displayedChild != ACTION_BAR_CHILD_BATCH) return; ArrayList items = new ArrayList(); gatherCheckedItems(mDrawerPage, items); - for(Item item : items) { - for(ItemView itemView : mScreen.getItemViewsForItem(item)) { + for (Item item : items) { + for (ItemView itemView : mScreen.getItemViewsForItem(item)) { itemView.setChecked(false); } } mBatchCheckedCount = 0; - if(on) { + if (on) { mPreviouslyDisplayedChild = mActionBar.getDisplayedChild(); mActionBar.setDisplayedChild(ACTION_BAR_CHILD_BATCH); showCustomActionBar(false); mAndroidActionBarDisplayedBeforeBatch = mIsAndroidActionBarDisplayed; - if(mIsAndroidActionBarDisplayed) { + if (mIsAndroidActionBarDisplayed) { mScreen.hideAndroidActionBar(); } } else { mActionBar.setDisplayedChild(mPreviouslyDisplayedChild); - if(mDrawerPage.config.adHideActionBar) { + if (mDrawerPage.config.adHideActionBar) { hideCustomActionBar(); } - if(mAndroidActionBarDisplayedBeforeBatch) { + if (mAndroidActionBarDisplayedBeforeBatch) { mScreen.showAndroidActionBar(mABOnCreateOptionsMenu, mABOnOptionsItemSelected); } } @@ -1098,13 +1096,13 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi itemView.setChecked(new_state); mBatchCheckedCount += new_state ? 1 : -1; updateBatchCheckedCount(mBatchCheckedCount); - if(mBatchCheckedCount == 0) { + if (mBatchCheckedCount == 0) { setBatchMode(false); } } private void updateBatchCheckedCount(int count) { - mBatchCount.setText(getString(R.string.ad_bc)+" "+count); + mBatchCount.setText(getString(R.string.ad_bc) + " " + count); } @Override @@ -1114,12 +1112,12 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi @Override protected void addFolder() { - if(LLApp.get().isFreeVersion()) { + if (LLApp.get().isFreeVersion()) { LLApp.get().showFeatureLockedDialog(this); return; } - ItemLayout il=mScreen.getTargetOrTopmostItemLayout(); + ItemLayout il = mScreen.getTargetOrTopmostItemLayout(); Page page = il.getPage(); Item item = Utils.addFolder(page, mScreen.getLastTouchedAddX(), mScreen.getLastTouchedAddY(), il.getCurrentScale(), true, getString(net.pierrox.lightning_launcher.R.string.default_folder_name)); @@ -1127,7 +1125,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi mUndoStack.storePageAddItem(item); enterEditMode(il, item); - if(!page.isFolder()) { + if (!page.isFolder()) { il.ensureCellVisible(item.getCell()); } } @@ -1140,23 +1138,24 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi @Override protected void configureBubbleForItem(int mode, ItemView itemView, List shortcuts) { Item item = itemView.getItem(); - if(mode == BUBBLE_MODE_ITEM_EM) { + if (mode == BUBBLE_MODE_ITEM_EM) { boolean is_folder = item instanceof Folder; boolean is_page_indicator = item instanceof PageIndicator; - if(mLayoutMode== Utils.LAYOUT_MODE_CUSTOM) { + if (mLayoutMode == Utils.LAYOUT_MODE_CUSTOM) { addBubbleItem(R.id.mi_edit, R.string.mi_customize); addBubbleItem(R.id.mi_position, R.string.mi_position); } - if(is_folder || is_page_indicator) { + if (is_folder || is_page_indicator) { addBubbleItem(R.id.mi_remove, R.string.mi_remove); } else { addBubbleItem(R.id.mi_actions, R.string.mi_actions); } - if(item.getPage().isFolder()) addBubbleItem(R.id.mi_move_out_of_folder, R.string.mi_move_out_of_folder); - } else if(mode == BUBBLE_MODE_ITEM_POSITION) { + if (item.getPage().isFolder()) + addBubbleItem(R.id.mi_move_out_of_folder, R.string.mi_move_out_of_folder); + } else if (mode == BUBBLE_MODE_ITEM_POSITION) { ItemConfig ic = item.getItemConfig(); - addBubbleItem(R.id.mi_pin, ic.pinMode!= ItemConfig.PinMode.NONE ? R.string.mi_unpin : R.string.mi_pin); + addBubbleItem(R.id.mi_pin, ic.pinMode != ItemConfig.PinMode.NONE ? R.string.mi_unpin : R.string.mi_pin); } else { super.configureBubbleForItem(mode, itemView, shortcuts); } @@ -1164,29 +1163,35 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi @Override protected void configureBubbleForContainer(int mode, ItemLayout il) { - if(mode == BUBBLE_MODE_DRAWER_MENU) { - boolean is_layout_custom=(mLayoutMode== Utils.LAYOUT_MODE_CUSTOM); + if (mode == BUBBLE_MODE_DRAWER_MENU) { + boolean is_layout_custom = (mLayoutMode == Utils.LAYOUT_MODE_CUSTOM); addBubbleItem(R.id.mi_es_refresh, R.string.mi_es_refresh); addBubbleItem(R.id.mi_v, R.string.v_m); - if(is_layout_custom) { + if (is_layout_custom) { addBubbleItem(R.id.mi_i, R.string.mi_i); } - if(mGlobalConfig.runScripts) { + if (mGlobalConfig.runScripts) { addBubbleItem(R.id.mi_s, R.string.mi_s); } addBubbleItem(R.id.mi_dm_customize, R.string.mi_es_settings); - } else if(mode == BUBBLE_MODE_DRAWER_VISIBILITY) { + } else if (mode == BUBBLE_MODE_DRAWER_VISIBILITY) { int handling = il.getAppDrawerHiddenHandling(); addBubbleItem(R.id.mi_va, toBold(R.string.v_a, handling == Item.APP_DRAWER_HIDDEN_ALL)); addBubbleItem(R.id.mi_vov, toBold(R.string.v_ov, handling == Item.APP_DRAWER_HIDDEN_ONLY_VISIBLE)); addBubbleItem(R.id.mi_voh, toBold(R.string.v_oh, handling == Item.APP_DRAWER_HIDDEN_ONLY_HIDDEN)); - } else if(mode == BUBBLE_MODE_DRAWER_MODE) { - if(hasMode(Utils.LAYOUT_MODE_CUSTOM)) addBubbleItem(R.id.mi_mode_custom, R.string.mi_mode_custom); - if(hasMode(Utils.LAYOUT_MODE_BY_NAME)) addBubbleItem(R.id.mi_mode_by_name, R.string.mi_mode_by_name); - if(hasMode(Utils.LAYOUT_MODE_FREQUENTLY_USED)) addBubbleItem(R.id.mi_mode_frequently_used, R.string.mi_mode_frequently_used); - if(hasMode(Utils.LAYOUT_MODE_RECENT_APPS)) addBubbleItem(R.id.mi_mode_recent_apps, R.string.mi_mode_recent_apps); - if(hasMode(Utils.LAYOUT_MODE_RECENTLY_UPDATED)) addBubbleItem(R.id.mi_mode_recently_updated, R.string.mi_mode_recently_updated); - if(hasMode(Utils.LAYOUT_MODE_RUNNING)) addBubbleItem(R.id.mi_mode_running, R.string.mi_mode_running); + } else if (mode == BUBBLE_MODE_DRAWER_MODE) { + if (hasMode(Utils.LAYOUT_MODE_CUSTOM)) + addBubbleItem(R.id.mi_mode_custom, R.string.mi_mode_custom); + if (hasMode(Utils.LAYOUT_MODE_BY_NAME)) + addBubbleItem(R.id.mi_mode_by_name, R.string.mi_mode_by_name); + if (hasMode(Utils.LAYOUT_MODE_FREQUENTLY_USED)) + addBubbleItem(R.id.mi_mode_frequently_used, R.string.mi_mode_frequently_used); + if (hasMode(Utils.LAYOUT_MODE_RECENT_APPS)) + addBubbleItem(R.id.mi_mode_recent_apps, R.string.mi_mode_recent_apps); + if (hasMode(Utils.LAYOUT_MODE_RECENTLY_UPDATED)) + addBubbleItem(R.id.mi_mode_recently_updated, R.string.mi_mode_recently_updated); + if (hasMode(Utils.LAYOUT_MODE_RUNNING)) + addBubbleItem(R.id.mi_mode_running, R.string.mi_mode_running); } else { super.configureBubbleForContainer(mode, il); } @@ -1194,7 +1199,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi private CharSequence toBold(int text, boolean bold) { CharSequence string = getString(text); - if(bold) { + if (bold) { SpannableString spannedLabel = new SpannableString(string); spannedLabel.setSpan(new StyleSpan(Typeface.BOLD), 0, string.length(), 0); string = spannedLabel; @@ -1220,26 +1225,31 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi @Override protected boolean displayBubbleButtonsForMode(int mode) { - switch(mode) { - case BUBBLE_MODE_DRAWER_MENU: return true; - case BUBBLE_MODE_DRAWER_MODE: return false; - case BUBBLE_MODE_DRAWER_VISIBILITY: return false; - case BUBBLE_MODE_ITEM_NO_EM: return mLayoutMode == Utils.LAYOUT_MODE_CUSTOM; - default: return super.displayBubbleButtonsForMode(mode); + switch (mode) { + case BUBBLE_MODE_DRAWER_MENU: + return true; + case BUBBLE_MODE_DRAWER_MODE: + return false; + case BUBBLE_MODE_DRAWER_VISIBILITY: + return false; + case BUBBLE_MODE_ITEM_NO_EM: + return mLayoutMode == Utils.LAYOUT_MODE_CUSTOM; + default: + return super.displayBubbleButtonsForMode(mode); } } @Override public void onClick(View v) { ItemLayout il; - boolean close_bubble=true; + boolean close_bubble = true; int id = v.getId(); - switch(id) { + switch (id) { case R.id.drawer_mode_grp: v.getHitRect(mTempRect); mTempRect.top = mTempRect.bottom; // hack, force the arrow to be positioned at the exact height - if(!closeBubble() || mBubbleMode!= BUBBLE_MODE_DRAWER_MODE) { + if (!closeBubble() || mBubbleMode != BUBBLE_MODE_DRAWER_MODE) { openBubble(BUBBLE_MODE_DRAWER_MODE, mScreen.getTargetOrTopmostItemLayout(), mTempRect); } close_bubble = false; @@ -1257,7 +1267,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi mScreen.setLastTouchEventForMenuBottom(false); v.getHitRect(mTempRect); mTempRect.top = mTempRect.bottom; // hack, force the arrow to be positioned at the exact height - if(!closeBubble() || mBubbleMode!= BUBBLE_MODE_DRAWER_MENU) { + if (!closeBubble() || mBubbleMode != BUBBLE_MODE_DRAWER_MENU) { openBubble(BUBBLE_MODE_DRAWER_MENU, mScreen.getTopmostItemLayout(), mTempRect); } close_bubble = false; @@ -1272,7 +1282,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi break; case R.id.mi_es_edit_layout: - if(!mEditMode) { + if (!mEditMode) { enterEditMode(mScreen.getTargetOrTopmostItemLayout(), null); } else { leaveEditMode(); @@ -1288,15 +1298,21 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi case R.id.mi_vov: case R.id.mi_voh: int vis = 0; - switch(id) { - case R.id.mi_va: vis = Item.APP_DRAWER_HIDDEN_ALL; break; - case R.id.mi_voh: vis = Item.APP_DRAWER_HIDDEN_ONLY_HIDDEN; break; - case R.id.mi_vov: vis = Item.APP_DRAWER_HIDDEN_ONLY_VISIBLE; break; + switch (id) { + case R.id.mi_va: + vis = Item.APP_DRAWER_HIDDEN_ALL; + break; + case R.id.mi_voh: + vis = Item.APP_DRAWER_HIDDEN_ONLY_HIDDEN; + break; + case R.id.mi_vov: + vis = Item.APP_DRAWER_HIDDEN_ONLY_VISIBLE; + break; } il = mScreen.getTargetOrTopmostItemLayout(); il.setAppDrawerHiddenHandling(vis); - if(mLayoutMode != Utils.LAYOUT_MODE_CUSTOM) { + if (mLayoutMode != Utils.LAYOUT_MODE_CUSTOM) { layoutItemsInTable(true); il.getHitRect(mTempRect); @@ -1304,13 +1320,13 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi il.getLocalInverseTransform().mapRect(mTempRectF); mTempRectF.round(mTempRect); il.computeBoundingBox(il.getWidth(), il.getHeight()); - if(!il.getItemsBoundingBox().contains(mTempRect)) { + if (!il.getItemsBoundingBox().contains(mTempRect)) { il.animateZoomTo(ItemLayout.POSITION_ORIGIN, 1); } } else { il.requestLayout(); } - if(mEditMode) { + if (mEditMode) { for (Item item : mEditItemLayout.getPage().items) { ItemView itemView = mEditItemLayout.getItemView(item); if (itemView.isSelected() && !itemView.isViewVisible()) { @@ -1321,7 +1337,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi break; case R.id.mi_es_refresh: - if(mLayoutMode== Utils.LAYOUT_MODE_RECENT_APPS || mLayoutMode== Utils.LAYOUT_MODE_RUNNING) { + if (mLayoutMode == Utils.LAYOUT_MODE_RECENT_APPS || mLayoutMode == Utils.LAYOUT_MODE_RUNNING) { setLayoutMode(mLayoutMode, true); } else { refreshAppDrawerItems(true); @@ -1334,7 +1350,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi break; case R.id.mi_mode_custom: - if((mSystemConfig.hints&SystemConfig.HINT_MY_DRAWER) == 0) { + if ((mSystemConfig.hints & SystemConfig.HINT_MY_DRAWER) == 0) { showDialog(DIALOG_MY_DRAWER); mSystemConfig.hints |= SystemConfig.HINT_MY_DRAWER; } @@ -1342,27 +1358,27 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi break; case R.id.mi_mode_by_name: - if(mEditMode) leaveEditMode(); + if (mEditMode) leaveEditMode(); setLayoutModeAnimated(Utils.LAYOUT_MODE_BY_NAME); break; case R.id.mi_mode_frequently_used: - if(mEditMode) leaveEditMode(); + if (mEditMode) leaveEditMode(); setLayoutModeAnimated(Utils.LAYOUT_MODE_FREQUENTLY_USED); break; case R.id.mi_mode_recent_apps: - if(mEditMode) leaveEditMode(); + if (mEditMode) leaveEditMode(); setLayoutModeAnimated(Utils.LAYOUT_MODE_RECENT_APPS); break; case R.id.mi_mode_recently_updated: - if(mEditMode) leaveEditMode(); + if (mEditMode) leaveEditMode(); setLayoutModeAnimated(Utils.LAYOUT_MODE_RECENTLY_UPDATED); break; case R.id.mi_mode_running: - if(mEditMode) leaveEditMode(); + if (mEditMode) leaveEditMode(); setLayoutModeAnimated(Utils.LAYOUT_MODE_RUNNING); break; @@ -1373,18 +1389,18 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi Item i = itemView.getItem(); mUndoStack.storeItemState(i); boolean will_hide = !i.isAppDrawerHidden(); - if(mEditMode && will_hide && itemView.isSelected()) { + if (mEditMode && will_hide && itemView.isSelected()) { itemView.setSelected(false); } i.setAppDrawerHidden(will_hide); i.getPage().setModified(); - if(mLayoutMode == Utils.LAYOUT_MODE_CUSTOM) { + if (mLayoutMode == Utils.LAYOUT_MODE_CUSTOM) { itemView.getParentItemLayout().requestLayout(); } } mUndoStack.storeGroupEnd(); - if(mLayoutMode != Utils.LAYOUT_MODE_CUSTOM) { + if (mLayoutMode != Utils.LAYOUT_MODE_CUSTOM) { layoutItemsInTable(true); } @@ -1397,7 +1413,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi break; case R.id.mi_kill: - if(LLApp.get().isFreeVersion()) { + if (LLApp.get().isFreeVersion()) { LLApp.get().showFeatureLockedDialog(this); } else { // use super class behavior but in addition, trigger a refresh if in running view @@ -1414,7 +1430,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi break; case R.id.mi_i: - if(mScreen.getTargetItemLayout() == null) { + if (mScreen.getTargetItemLayout() == null) { findViewById(R.id.drawer_more).getHitRect(mTempRect); openBubble(BUBBLE_MODE_ITEMS, mBubbleItemLayout, mTempRect); } else { @@ -1437,7 +1453,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi return; } - if(close_bubble) { + if (close_bubble) { closeBubble(); } } @@ -1457,9 +1473,9 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi @Override protected void menuActionConfirmRemoveItem() { final ArrayList actionItems = getActionItems(); - if(actionItems.size()==1) { + if (actionItems.size() == 1) { Item item = actionItems.get(0); - if(item.getClass() == Shortcut.class) { + if (item.getClass() == Shortcut.class) { startActivity(new Intent(Intent.ACTION_DELETE, Uri.parse("package:" + Utils.getPackageNameForItem(item)))); return; } @@ -1469,7 +1485,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi } private void ensureMyDrawerMode() { - if(mLayoutMode != Utils.LAYOUT_MODE_CUSTOM) { + if (mLayoutMode != Utils.LAYOUT_MODE_CUSTOM) { setLayoutMode(Utils.LAYOUT_MODE_CUSTOM, false, true); Toast toast = Toast.makeText(this, R.string.ad_mdh, Toast.LENGTH_SHORT); toast.setGravity(Gravity.CENTER, 0, 0); @@ -1480,7 +1496,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi private void doAddForBatchMode() { ArrayList items = new ArrayList<>(); gatherCheckedItems(mDrawerPage, items); - for(Item item : items) { + for (Item item : items) { addItemToLauncher(item); } setBatchMode(false); @@ -1496,13 +1512,13 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi // hack : in the app drawer, views are recreated because of the removal ItemView[] ivs = mScreen.getItemViewsForItem(item); itemView = ivs[0]; - if(item instanceof Folder) { + if (item instanceof Folder) { moveFolderItemsToDrawer(itemView); } ivs = mScreen.getItemViewsForItem(item); itemView = ivs[0]; - if(item instanceof Folder || item instanceof PageIndicator) { + if (item instanceof Folder || item instanceof PageIndicator) { itemView.setSelected(false); Page page = item.getPage(); mUndoStack.storePageRemoveItem(item); @@ -1514,12 +1530,12 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi @Override public int[] onHierarchyScreenGetRootPages() { - return new int[] { Page.APP_DRAWER_PAGE }; + return new int[]{Page.APP_DRAWER_PAGE}; } private void addItemToLauncher(Item item) { Page pageTo = item.getPage().getEngine().getOrLoadPage(LLApp.get().getActiveDashboardPage()); - if(item.getClass() == Folder.class) { + if (item.getClass() == Folder.class) { Folder f = (Folder) item; Intent intent = new Intent(this, Dashboard.class); intent.putExtra(LightningIntent.INTENT_EXTRA_ACTION, GlobalConfig.OPEN_FOLDER); @@ -1536,7 +1552,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi findViewById(R.id.drawer_progress).setVisibility(View.VISIBLE); mItemLayout.setVisibility(View.GONE); - if(animate_hide) { + if (animate_hide) { mItemLayout.startAnimation(AnimationUtils.loadAnimation(AppDrawerX.this, android.R.anim.fade_out)); } @@ -1555,14 +1571,14 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi @Override protected void onPostExecute(Void result) { - if(mItemLayout != null) { + if (mItemLayout != null) { mSavedItemLayoutLocalTransformCustom.reset(); mSavedItemLayoutLocalTransformByName.reset(); mItemLayout.setLocalTransform(mSavedItemLayoutLocalTransformCustom); drawer_actions.setVisibility(View.VISIBLE); setLayoutMode(mLayoutMode, true); } - if(mItemLayout != null) { + if (mItemLayout != null) { findViewById(R.id.drawer_progress).setVisibility(View.GONE); mItemLayout.setVisibility(View.VISIBLE); mItemLayout.startAnimation(AnimationUtils.loadAnimation(AppDrawerX.this, android.R.anim.fade_in)); @@ -1574,7 +1590,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi @Override public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { ItemView itemView = getFirstVisibleItemView(); - if(itemView != null) { + if (itemView != null) { mScreen.launchItem(itemView); return true; } else { @@ -1591,11 +1607,11 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi @Override public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) { filterApps(charSequence.toString()); - if(mSearchFocusedItemView != null) { + if (mSearchFocusedItemView != null) { mSearchFocusedItemView.setFocused(false); } ItemView itemView = getFirstVisibleItemView(); - if(itemView != null) { + if (itemView != null) { mSearchFocusedItemView = itemView; mSearchFocusedItemView.setFocused(true); } @@ -1607,8 +1623,8 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi } private ItemView getFirstVisibleItemView() { - for(Item item : mItemLayout.getPage().items) { - if(item.isVisible()) { + for (Item item : mItemLayout.getPage().items) { + if (item.isVisible()) { return mItemLayout.getItemView(item); } } @@ -1628,7 +1644,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi } mHandler.removeCallbacks(mHideCustomActionBarRunnable); - if(hide_later && mActionBar.getDisplayedChild() == ACTION_BAR_CHILD_DRAWER_ACTIONS) { + if (hide_later && mActionBar.getDisplayedChild() == ACTION_BAR_CHILD_DRAWER_ACTIONS) { mHandler.postDelayed(mHideCustomActionBarRunnable, ACTION_BAR_HIDE_DELAY); } } @@ -1644,36 +1660,29 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi mActionBar.startAnimation(as); } - private Runnable mHideCustomActionBarRunnable = new Runnable() { - @Override - public void run() { - hideCustomActionBar(); - } - }; - private void moveFolderItemsToDrawer(ItemView folderItemView) { FolderView fv = mScreen.findFolderView(folderItemView, null); - if(fv == null) { - fv = mScreen.openFolder((Folder)folderItemView.getItem(), folderItemView, null, true); + if (fv == null) { + fv = mScreen.openFolder((Folder) folderItemView.getItem(), folderItemView, null, true); } ItemLayout ilFrom = fv.getItemLayout(); Page folder_page = ilFrom.getPage(); ArrayList items = folder_page.items; - for(int j=items.size()-1; j>=0; j--) { - Item i=items.get(j); + for (int j = items.size() - 1; j >= 0; j--) { + Item i = items.get(j); ItemView itemView = ilFrom.getItemView(i); - if(i.getClass()==Folder.class) { + if (i.getClass() == Folder.class) { moveFolderItemsToDrawer(itemView); } saveInitialItemViewGeometry(itemView); int old_id = i.getId(); - Item newItem = Utils.moveItem (i, mDrawerPage, Utils.POSITION_AUTO, Utils.POSITION_AUTO, 1, Item.NO_ID); + Item newItem = Utils.moveItem(i, mDrawerPage, Utils.POSITION_AUTO, Utils.POSITION_AUTO, 1, Item.NO_ID); mUndoStack.storePageItemMove(mItemLayout.getItemView(newItem), old_id, mOriginalItemsGeometry.get(old_id)); } } private class MergedPage extends Page { - private HashSet mPageIds; + private final HashSet mPageIds; public MergedPage(LightningEngine engine, PageConfig c, ArrayList items) { super(engine, Page.MERGED_APP_DRAWER_PAGE); @@ -1682,7 +1691,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi this.id = Page.APP_DRAWER_PAGE; mPageIds = new HashSet<>(); - for(Item i : items) { + for (Item i : items) { mPageIds.add(Utils.getPageForItem(i)); } } @@ -1690,7 +1699,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi @Override public void setCurrentViewSize(int width, int height, float cell_width, float cell_height) { super.setCurrentViewSize(width, height, cell_width, cell_height); - for(int i : mPageIds) { + for (int i : mPageIds) { mEngine.getOrLoadPage(i).setCurrentViewSize(width, height, cell_width, cell_height); } } @@ -1714,7 +1723,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi @Override public ItemLayout loadRootItemLayout(int page, boolean reset_navigation_history, boolean displayImmediately, boolean animate) { - if(page == mDrawerPage.id) { + if (page == mDrawerPage.id) { setLayoutMode(mLayoutMode, true); return mItemLayout; } else { @@ -1729,11 +1738,11 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi @Override public ItemLayout[] getItemLayoutsForPage(int pageId) { - if(mLayoutMode == Utils.LAYOUT_MODE_CUSTOM) { + if (mLayoutMode == Utils.LAYOUT_MODE_CUSTOM) { return super.getItemLayoutsForPage(pageId); } else { // pretend that the main item layout fits all pages (it does because it includes views from item belonging to other folders) - if(mAllDrawerPageIDs.contains(pageId)) { + if (mAllDrawerPageIDs.contains(pageId)) { return new ItemLayout[]{mItemLayout}; } else { return new ItemLayout[0]; @@ -1744,7 +1753,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi @Override public void showAndroidActionBar(Function onCreateOptionsMenu, Function onOptionsItemSelected) { super.showAndroidActionBar(onCreateOptionsMenu, onOptionsItemSelected); - if(isAndroidActionBarSupported()) { + if (isAndroidActionBarSupported()) { hideCustomActionBar(); } } @@ -1752,8 +1761,8 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi @Override public void hideAndroidActionBar() { super.hideAndroidActionBar(); - if(isAndroidActionBarSupported()) { - if(!mDrawerPage.config.adHideActionBar) { + if (isAndroidActionBarSupported()) { + if (!mDrawerPage.config.adHideActionBar) { showCustomActionBar(false); } } @@ -1789,7 +1798,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi @Override public void onItemLayoutLongClicked(ItemLayout item_layout, int x, int y) { setLastTouchEventForItemLayout(item_layout, x, y); - if(mEditMode) { + if (mEditMode) { mEditItemLayout.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); unselectAllItems(); } @@ -1798,21 +1807,21 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi @Override public void onItemLayoutZoomChanged(float scale) { - if(mLayoutMode != Utils.LAYOUT_MODE_CUSTOM) { + if (mLayoutMode != Utils.LAYOUT_MODE_CUSTOM) { layoutItemsInTable(false); } } @Override public void onItemLayoutPinchStart() { - if(mLayoutMode != Utils.LAYOUT_MODE_CUSTOM) { - mScaleBeforePinch=mItemLayout.getCurrentScale(); + if (mLayoutMode != Utils.LAYOUT_MODE_CUSTOM) { + mScaleBeforePinch = mItemLayout.getCurrentScale(); } } @Override public boolean onItemLayoutPinch(float scale) { - if(mLayoutMode != Utils.LAYOUT_MODE_CUSTOM) { + if (mLayoutMode != Utils.LAYOUT_MODE_CUSTOM) { mItemLayout.zoomTo(mScaleBeforePinch * scale); return false; } else { @@ -1822,15 +1831,15 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi @Override public void onItemLayoutPinchEnd(boolean from_user) { - if(mLayoutMode != Utils.LAYOUT_MODE_CUSTOM) { + if (mLayoutMode != Utils.LAYOUT_MODE_CUSTOM) { layoutItemsInTable(true); - if(from_user) { + if (from_user) { // need an epsilon to ensure that floating point rounding errors do not reach the upper cell - int x_max=(int) (mItemLayout.getWidth()/(mItemLayout.getCurrentScale()*mItemLayout.getCellWidth())); - if(x_max<1) x_max=1; - if(x_max>40) x_max=40; - float scale=mItemLayout.getWidth()/(float)(x_max*mItemLayout.getCellWidth())-0.001f; + int x_max = (int) (mItemLayout.getWidth() / (mItemLayout.getCurrentScale() * mItemLayout.getCellWidth())); + if (x_max < 1) x_max = 1; + if (x_max > 40) x_max = 40; + float scale = mItemLayout.getWidth() / (x_max * mItemLayout.getCellWidth()) - 0.001f; mItemLayout.animateZoomTo(ItemLayout.POSITION_FREE, scale); } } @@ -1838,15 +1847,15 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi @Override public void onItemLayoutOnLayoutDone(ItemLayout item_layout) { - if(mLayoutMode != Utils.LAYOUT_MODE_CUSTOM && item_layout.getPage().id == Page.APP_DRAWER_PAGE) { + if (mLayoutMode != Utils.LAYOUT_MODE_CUSTOM && item_layout.getPage().id == Page.APP_DRAWER_PAGE) { layoutItemsInTable(false); } } @Override public void onItemLayoutPositionChanged(ItemLayout il, float mCurrentDx, float mCurrentDy, float mCurrentScale) { - if(mDrawerPage != null && mDrawerPage.config.adHideActionBar && mDrawerPage.config.adDisplayABOnScroll) { - if(mActionBar.getDisplayedChild() != ACTION_BAR_CHILD_SEARCH && !mIsAndroidActionBarDisplayed) { + if (mDrawerPage != null && mDrawerPage.config.adHideActionBar && mDrawerPage.config.adDisplayABOnScroll) { + if (mActionBar.getDisplayedChild() != ACTION_BAR_CHILD_SEARCH && !mIsAndroidActionBarDisplayed) { showCustomActionBar(true); } } @@ -1856,7 +1865,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi @Override public void onItemLayoutSwipeLeft(ItemLayout item_layout) { final PageConfig config = mDrawerPage.config; - if(config.swipeRight.action == GlobalConfig.UNSET && config.scrollingDirection!=PageConfig.ScrollingDirection.X && !mSearchMode) { + if (config.swipeRight.action == GlobalConfig.UNSET && config.scrollingDirection != PageConfig.ScrollingDirection.X && !mSearchMode) { previousLayoutMode(); } else { super.onItemLayoutSwipeLeft(item_layout); @@ -1866,7 +1875,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi @Override public void onItemLayoutSwipe2Left(ItemLayout item_layout) { final PageConfig config = mDrawerPage.config; - if(config.swipe2Left.action == GlobalConfig.UNSET && config.scrollingDirection!=PageConfig.ScrollingDirection.X && !mSearchMode) { + if (config.swipe2Left.action == GlobalConfig.UNSET && config.scrollingDirection != PageConfig.ScrollingDirection.X && !mSearchMode) { previousLayoutMode(); } else { super.onItemLayoutSwipe2Left(item_layout); @@ -1876,7 +1885,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi @Override public void onItemLayoutSwipeRight(ItemLayout item_layout) { final PageConfig config = mDrawerPage.config; - if(config.swipeRight.action == GlobalConfig.UNSET && config.scrollingDirection!=PageConfig.ScrollingDirection.X && !mSearchMode) { + if (config.swipeRight.action == GlobalConfig.UNSET && config.scrollingDirection != PageConfig.ScrollingDirection.X && !mSearchMode) { nextLayoutMode(); } else { super.onItemLayoutSwipeRight(item_layout); @@ -1886,7 +1895,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi @Override public void onItemLayoutSwipe2Right(ItemLayout item_layout) { final PageConfig config = mDrawerPage.config; - if(config.swipe2Right.action == GlobalConfig.UNSET && config.scrollingDirection!=PageConfig.ScrollingDirection.X && !mSearchMode) { + if (config.swipe2Right.action == GlobalConfig.UNSET && config.scrollingDirection != PageConfig.ScrollingDirection.X && !mSearchMode) { nextLayoutMode(); } else { super.onItemLayoutSwipe2Right(item_layout); @@ -1896,7 +1905,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi @Override public void onItemLayoutSwipeUp(ItemLayout item_layout) { final PageConfig config = mDrawerPage.config; - if(config.swipeUp.action == GlobalConfig.UNSET && config.scrollingDirection==PageConfig.ScrollingDirection.X && !mSearchMode) { + if (config.swipeUp.action == GlobalConfig.UNSET && config.scrollingDirection == PageConfig.ScrollingDirection.X && !mSearchMode) { nextLayoutMode(); } else { super.onItemLayoutSwipeUp(item_layout); @@ -1906,7 +1915,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi @Override public void onItemLayoutSwipe2Up(ItemLayout item_layout) { final PageConfig config = mDrawerPage.config; - if(config.swipe2Up.action == GlobalConfig.UNSET && config.scrollingDirection==PageConfig.ScrollingDirection.X && !mSearchMode) { + if (config.swipe2Up.action == GlobalConfig.UNSET && config.scrollingDirection == PageConfig.ScrollingDirection.X && !mSearchMode) { nextLayoutMode(); } else { super.onItemLayoutSwipe2Up(item_layout); @@ -1916,7 +1925,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi @Override public void onItemLayoutSwipeDown(ItemLayout item_layout) { final PageConfig config = mDrawerPage.config; - if(config.swipeDown.action == GlobalConfig.UNSET && config.scrollingDirection==PageConfig.ScrollingDirection.X && !mSearchMode) { + if (config.swipeDown.action == GlobalConfig.UNSET && config.scrollingDirection == PageConfig.ScrollingDirection.X && !mSearchMode) { previousLayoutMode(); } else { super.onItemLayoutSwipeDown(item_layout); @@ -1926,7 +1935,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi @Override public void onItemLayoutSwipe2Down(ItemLayout item_layout) { final PageConfig config = mDrawerPage.config; - if(config.swipe2Down.action == GlobalConfig.UNSET && config.scrollingDirection==PageConfig.ScrollingDirection.X && !mSearchMode) { + if (config.swipe2Down.action == GlobalConfig.UNSET && config.scrollingDirection == PageConfig.ScrollingDirection.X && !mSearchMode) { previousLayoutMode(); } else { super.onItemLayoutSwipe2Down(item_layout); @@ -1937,9 +1946,9 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi public void onItemViewClicked(ItemView itemView) { Item item = itemView.getItem(); Class itemClass = item.getClass(); - boolean is_folder = itemClass ==Folder.class; - if(isSelectForAdd() && !is_folder) { - if(mActionBar.getDisplayedChild() == ACTION_BAR_CHILD_BATCH) { + boolean is_folder = itemClass == Folder.class; + if (isSelectForAdd() && !is_folder) { + if (mActionBar.getDisplayedChild() == ACTION_BAR_CHILD_BATCH) { checkUncheckItemView(itemView); } else { Intent i = new Intent(); @@ -1947,15 +1956,15 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi setResult(RESULT_OK, i); finish(); } - } else if(isSelectForPick() && !is_folder) { - Shortcut s=(Shortcut) item; + } else if (isSelectForPick() && !is_folder) { + Shortcut s = (Shortcut) item; setResult(RESULT_OK, s.getIntent()); finish(); } else { - if(itemClass == Shortcut.class && !mEditMode) { + if (itemClass == Shortcut.class && !mEditMode) { Intent intent = ((Shortcut) item).getIntent(); Bundle extras = intent.getExtras(); - if(extras == null || extras.size() == 0) { + if (extras == null || extras.size() == 0) { ComponentName cn = intent.getComponent(); if (mThisCn.compareTo(cn) == 0) { PhoneUtils.startSettings(mContext, new ContainerPath(Page.APP_DRAWER_PAGE), false); @@ -1973,12 +1982,12 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi @Override public void onItemViewLongClicked(ItemView itemView) { - if(!mEditMode && isSelectForAdd()) { + if (!mEditMode && isSelectForAdd()) { setBatchMode(true); checkUncheckItemView(itemView); return; } - if(mLayoutMode == Utils.LAYOUT_MODE_CUSTOM) { + if (mLayoutMode == Utils.LAYOUT_MODE_CUSTOM) { super.onItemViewLongClicked(itemView); } else { openBubble(BUBBLE_MODE_ITEM_NO_EM, itemView); @@ -1993,20 +2002,20 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi @Override protected void zoomFullScale(ItemLayout il) { - if(mLayoutMode == Utils.LAYOUT_MODE_CUSTOM) { + if (mLayoutMode == Utils.LAYOUT_MODE_CUSTOM) { il.animateZoomTo(ItemLayout.POSITION_FULL_SCALE, 0); } else { - final float CW=mItemLayout.getCellWidth(); - final float CH=mItemLayout.getCellHeight(); + final float CW = mItemLayout.getCellWidth(); + final float CH = mItemLayout.getCellHeight(); - int N=(int)(mItemLayout.getWidth() / CW); //mActivePage.config.gridLayoutModeNumColumns; + int N = (int) (mItemLayout.getWidth() / CW); //mActivePage.config.gridLayoutModeNumColumns; - float scale=1; - float r=mItemLayout.getWidth()/(float)mItemLayout.getHeight(); - for(int x=N+1; x<100; x++) { - int y=(mVisibleItemsCount+x-1)/x; - if((x*CW)/((float)y*CH) >= r) { - scale=N/(float)x; + float scale = 1; + float r = mItemLayout.getWidth() / (float) mItemLayout.getHeight(); + for (int x = N + 1; x < 100; x++) { + int y = (mVisibleItemsCount + x - 1) / x; + if ((x * CW) / ((float) y * CH) >= r) { + scale = N / (float) x; break; } } @@ -2020,7 +2029,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi public void launchShortcut(ShortcutView shortcutView) { super.launchShortcut(shortcutView); - if(mDrawerPage.config.autoExit) { + if (mDrawerPage.config.autoExit) { finish(); } } @@ -2028,7 +2037,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi @Override public void onPageItemAdded(Item item) { super.onPageItemAdded(item); - if(item.getPage().id == mItemLayout.getPage().id) { + if (item.getPage().id == mItemLayout.getPage().id) { setLayoutMode(mLayoutMode, true); } } @@ -2036,7 +2045,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi @Override public void onPageItemRemoved(Page page, Item item) { super.onPageItemRemoved(page, item); - if(page.id == mItemLayout.getPage().id) { + if (page.id == mItemLayout.getPage().id) { setLayoutMode(mLayoutMode, true); } } @@ -2044,7 +2053,7 @@ public class AppDrawerX extends Dashboard implements EditTextIme.OnEditTextImeLi @Override public void onPageModified(Page page) { super.onPageModified(page); - if(page.id == mItemLayout.getPage().id) { + if (page.id == mItemLayout.getPage().id) { setLayoutMode(mLayoutMode, true); } } diff --git a/app/llx/app/src/main/java/net/pierrox/lightning_launcher/activities/ApplyTemplate.java b/app/llx/app/src/main/java/net/pierrox/lightning_launcher/activities/ApplyTemplate.java index 05003ff..97052a2 100644 --- a/app/llx/app/src/main/java/net/pierrox/lightning_launcher/activities/ApplyTemplate.java +++ b/app/llx/app/src/main/java/net/pierrox/lightning_launcher/activities/ApplyTemplate.java @@ -24,40 +24,6 @@ SOFTWARE. package net.pierrox.lightning_launcher.activities; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.Method; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; -import java.util.zip.ZipOutputStream; - -import net.pierrox.lightning_launcher.API; -import net.pierrox.lightning_launcher.LLApp; -import net.pierrox.lightning_launcher.configuration.GlobalConfig; -import net.pierrox.lightning_launcher.data.BackupRestoreTool; -import net.pierrox.lightning_launcher.data.FileUtils; -import net.pierrox.lightning_launcher.data.Item; -import net.pierrox.lightning_launcher.data.Page; -import net.pierrox.lightning_launcher.engine.LightningEngine; -import net.pierrox.lightning_launcher.data.PageProcessor; -import net.pierrox.lightning_launcher.data.Utils; -import net.pierrox.lightning_launcher.data.Widget; -import net.pierrox.lightning_launcher.script.ScriptManager; -import net.pierrox.lightning_launcher.script.Script; -import net.pierrox.lightning_launcher.template.LLTemplateAPI; -import net.pierrox.lightning_launcher_extreme.R; - -import org.json.JSONException; -import org.json.JSONObject; - import android.Manifest; import android.app.Activity; import android.app.AlertDialog; @@ -89,52 +55,49 @@ import android.widget.CheckBox; import android.widget.RadioButton; import android.widget.Toast; +import net.pierrox.lightning_launcher.API; +import net.pierrox.lightning_launcher.LLApp; +import net.pierrox.lightning_launcher.configuration.GlobalConfig; +import net.pierrox.lightning_launcher.data.BackupRestoreTool; +import net.pierrox.lightning_launcher.data.FileUtils; +import net.pierrox.lightning_launcher.data.Item; +import net.pierrox.lightning_launcher.data.Page; +import net.pierrox.lightning_launcher.data.PageProcessor; +import net.pierrox.lightning_launcher.data.Utils; +import net.pierrox.lightning_launcher.data.Widget; +import net.pierrox.lightning_launcher.engine.LightningEngine; +import net.pierrox.lightning_launcher.script.Script; +import net.pierrox.lightning_launcher.script.ScriptManager; +import net.pierrox.lightning_launcher.template.LLTemplateAPI; +import net.pierrox.lightning_launcher_extreme.R; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Method; +import java.nio.charset.StandardCharsets; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import java.util.zip.ZipOutputStream; + public class ApplyTemplate extends ResourceWrapperActivity { + /*package*/ static final String INTENT_EXTRA_PATH = "p"; + /*package*/ static final String INTENT_EXTRA_URI = "u"; private static final int DIALOG_CONFIRM_APPLY = 1; private static final int DIALOG_NEED_UPGRADE = 2; private static final int DIALOG_WARNING = 3; - private static final int REQUEST_BIND_APPWIDGET = 1; private static final int REQUEST_SELECT_SCREEN_FOR_GOTO = 2; - - /*package*/ static final String INTENT_EXTRA_PATH = "p"; - /*package*/ static final String INTENT_EXTRA_URI = "u"; - - private enum ApplyMode { - REPLACE, - MERGE, - UPDATE - } - - private ComponentName mTemplateCN; - private String mTemplateDisplayName; - private File mTemplateFile; - private Uri mTemplateUri; - - private boolean mBackupFirst; - private ApplyMode mApplyMode = ApplyMode.MERGE; - private boolean mLoadWallpaper; - - private int mLLVersionFrom; - - private boolean mWarningFreeVersion; - private boolean mWarningScreen; - private boolean mWarningWidget; - - private SparseArray mAppWidgetsToBind; - private ParcelableSparseIntArray mNewAppWidgetIds; - - private int mBindWidgetOldId; - private int mBindWidgetNewId; - private int mFromScreenDpi; - private int mFromScreenWidth; - private int mFromScreenHeight; - private int mFromStatusBarHeight; - - private File mAppBaseDir; - - private ArrayList mImportedPages; - private static Method sBindAppWidgetIdIfAllowed; static { @@ -143,24 +106,48 @@ public class ApplyTemplate extends ResourceWrapperActivity { } catch (NoSuchMethodException e) { } } - + + private ComponentName mTemplateCN; + private String mTemplateDisplayName; + private File mTemplateFile; + private Uri mTemplateUri; + private boolean mBackupFirst; + private ApplyMode mApplyMode = ApplyMode.MERGE; + private boolean mLoadWallpaper; + private int mLLVersionFrom; + private boolean mWarningFreeVersion; + private boolean mWarningScreen; + private boolean mWarningWidget; + private SparseArray mAppWidgetsToBind; + private ParcelableSparseIntArray mNewAppWidgetIds; + private int mBindWidgetOldId; + private int mBindWidgetNewId; + private int mFromScreenDpi; + private int mFromScreenWidth; + private int mFromScreenHeight; + private int mFromStatusBarHeight; + private File mAppBaseDir; + private ArrayList mImportedPages; + private ProgressDialog mDialog; + private LinkedList> mAppWidgetsToLoad; + @Override protected void onCreate(Bundle savedInstanceState) { Utils.setTheme(this, Utils.APP_THEME); super.onCreate(savedInstanceState); - + mAppBaseDir = LLApp.get().getAppEngine().getBaseDir(); - if(getIntent().hasExtra(INTENT_EXTRA_PATH)) { + if (getIntent().hasExtra(INTENT_EXTRA_PATH)) { mTemplateFile = new File(getIntent().getStringExtra(INTENT_EXTRA_PATH)); mTemplateDisplayName = mTemplateFile.getName(); - } else if(getIntent().hasExtra(INTENT_EXTRA_URI)) { + } else if (getIntent().hasExtra(INTENT_EXTRA_URI)) { mTemplateUri = getIntent().getParcelableExtra(INTENT_EXTRA_URI); mTemplateDisplayName = mTemplateUri.getLastPathSegment(); } else { mTemplateCN = getIntent().getParcelableExtra(LLTemplateAPI.INTENT_TEMPLATE_COMPONENT_NAME); - if(mTemplateCN == null) { + if (mTemplateCN == null) { finish(); return; } @@ -169,7 +156,7 @@ public class ApplyTemplate extends ResourceWrapperActivity { Intent filter = new Intent(); filter.setComponent(mTemplateCN); List ris = pm.queryIntentActivities(filter, 0); - if(ris.size() != 1) { + if (ris.size() != 1) { finish(); return; } @@ -177,7 +164,7 @@ public class ApplyTemplate extends ResourceWrapperActivity { mTemplateDisplayName = ris.get(0).activityInfo.loadLabel(pm).toString(); } - if(savedInstanceState != null) { + if (savedInstanceState != null) { mFromScreenDpi = savedInstanceState.getInt("sd"); mFromScreenWidth = savedInstanceState.getInt("sw"); mFromScreenHeight = savedInstanceState.getInt("sh"); @@ -187,25 +174,25 @@ public class ApplyTemplate extends ResourceWrapperActivity { mWarningFreeVersion = savedInstanceState.getBoolean("wx"); mWarningScreen = savedInstanceState.getBoolean("ws"); mWarningWidget = savedInstanceState.getBoolean("ww"); - + mAppWidgetsToBind = savedInstanceState.getSparseParcelableArray("wb"); mNewAppWidgetIds = savedInstanceState.getParcelable("nw"); mBindWidgetOldId = savedInstanceState.getInt("oi"); mBindWidgetNewId = savedInstanceState.getInt("ni"); int[] pages_id = savedInstanceState.getIntArray("ip"); - if(pages_id != null) { - mImportedPages = new ArrayList(); - LightningEngine engine = LLApp.get().getEngine(getExtractedTemplateDir(), true); - for(int p : pages_id) { - mImportedPages.add(engine.getOrLoadPage(p)); - } + if (pages_id != null) { + mImportedPages = new ArrayList(); + LightningEngine engine = LLApp.get().getEngine(getExtractedTemplateDir(), true); + for (int p : pages_id) { + mImportedPages.add(engine.getOrLoadPage(p)); + } } mApplyMode = ApplyMode.values()[savedInstanceState.getInt("am")]; } - if(checkPermissions( + if (checkPermissions( new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, - new int[] { R.string.pr_r6, R.string.pr_r7}, + new int[]{R.string.pr_r6, R.string.pr_r7}, REQUEST_PERMISSION_BASE)) { showDialog(DIALOG_CONFIRM_APPLY); } @@ -213,7 +200,7 @@ public class ApplyTemplate extends ResourceWrapperActivity { @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { - if(areAllPermissionsGranted(grantResults, R.string.pr_f4)) { + if (areAllPermissionsGranted(grantResults, R.string.pr_f4)) { showDialog(DIALOG_CONFIRM_APPLY); } } @@ -230,18 +217,18 @@ public class ApplyTemplate extends ResourceWrapperActivity { outState.putBoolean("wx", mWarningFreeVersion); outState.putBoolean("ws", mWarningScreen); outState.putBoolean("ww", mWarningWidget); - + outState.putSparseParcelableArray("wb", mAppWidgetsToBind); outState.putParcelable("nw", mNewAppWidgetIds); outState.putInt("oi", mBindWidgetOldId); outState.putInt("ni", mBindWidgetNewId); - if(mImportedPages != null) { - int l = mImportedPages.size(); - int[] pages_id = new int[l]; - for(int i=0; i Utils.getMyPackageVersion(ApplyTemplate.this)) { + if (mLLVersionFrom > Utils.getMyPackageVersion(ApplyTemplate.this)) { showDialog(DIALOG_NEED_UPGRADE); return; } @@ -399,11 +389,11 @@ public class ApplyTemplate extends ResourceWrapperActivity { mFromScreenHeight = manifest.getInt(BackupRestoreTool.MANIFEST_SCREEN_HEIGHT); mFromStatusBarHeight = manifest.getInt(BackupRestoreTool.MANIFEST_SB_HEIGHT); int screenDensity = manifest.getInt(BackupRestoreTool.MANIFEST_SCREEN_DENSITY); - mWarningScreen = (mFromScreenWidth!=dm.widthPixels || mFromScreenHeight!=dm.heightPixels || screenDensity!=dm.densityDpi); + mWarningScreen = (mFromScreenWidth != dm.widthPixels || mFromScreenHeight != dm.heightPixels || screenDensity != dm.densityDpi); - mWarningWidget = sBindAppWidgetIdIfAllowed==null; + mWarningWidget = sBindAppWidgetIdIfAllowed == null; - if(mWarningFreeVersion || mWarningScreen || mWarningWidget) { + if (mWarningFreeVersion || mWarningScreen || mWarningWidget) { showDialog(DIALOG_WARNING); } else { applyTemplate(); @@ -413,34 +403,32 @@ public class ApplyTemplate extends ResourceWrapperActivity { } } } - }.execute((Void)null); + }.execute((Void) null); } - private ProgressDialog mDialog; - private File getExtractedTemplateDir() { - String tempTemplatePath = FileUtils.LL_TMP_DIR+"/template"; + String tempTemplatePath = FileUtils.LL_TMP_DIR + "/template"; return new File(tempTemplatePath); } private void applyTemplate() { new AsyncTask() { - private File mTemplateDir; - private LightningEngine mEngineFrom; - private LightningEngine mEngineTo; - private SparseIntArray mTranslatedPageIds; - private SparseIntArray mTranslatedScriptIds; - + private File mTemplateDir; + private LightningEngine mEngineFrom; + private LightningEngine mEngineTo; + private SparseIntArray mTranslatedPageIds; + private SparseIntArray mTranslatedScriptIds; + @Override protected void onPreExecute() { - mTemplateDir = getExtractedTemplateDir(); - mEngineFrom = LLApp.get().getEngine(mTemplateDir, false); - mEngineTo = LLApp.get().getAppEngine(); - mImportedPages = new ArrayList<>(); - mTranslatedPageIds = null; - mTranslatedScriptIds = null; - + mTemplateDir = getExtractedTemplateDir(); + mEngineFrom = LLApp.get().getEngine(mTemplateDir, false); + mEngineTo = LLApp.get().getAppEngine(); + mImportedPages = new ArrayList<>(); + mTranslatedPageIds = null; + mTranslatedScriptIds = null; + mDialog = new ProgressDialog(ApplyTemplate.this); mDialog.setMessage(getString(mBackupFirst ? R.string.backup_in_progress : R.string.apply_tmpl_g)); mDialog.setCancelable(false); @@ -450,23 +438,23 @@ public class ApplyTemplate extends ResourceWrapperActivity { @Override protected Integer doInBackground(Void... voids) { Context context = ApplyTemplate.this; - if(mBackupFirst) { - SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH-mm"); - String backup_name=sdf.format(new Date()); - String backup_path= FileUtils.LL_EXT_DIR +"/"+getString(R.string.backup_d)+"-"+backup_name; + if (mBackupFirst) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH-mm"); + String backup_name = sdf.format(new Date()); + String backup_path = FileUtils.LL_EXT_DIR + "/" + getString(R.string.backup_d) + "-" + backup_name; - BackupRestoreTool.BackupConfig backup_config=new BackupRestoreTool.BackupConfig(); + BackupRestoreTool.BackupConfig backup_config = new BackupRestoreTool.BackupConfig(); - backup_config.context=context; - backup_config.pathFrom=mAppBaseDir.getAbsolutePath(); - backup_config.pathTo=backup_path; - backup_config.includeWidgetsData=true; - backup_config.includeWallpaper=true; - backup_config.includeFonts=true; + backup_config.context = context; + backup_config.pathFrom = mAppBaseDir.getAbsolutePath(); + backup_config.pathTo = backup_path; + backup_config.includeWidgetsData = true; + backup_config.includeWallpaper = true; + backup_config.includeFonts = true; Exception exception = BackupRestoreTool.backup(backup_config); - if(exception != null) { + if (exception != null) { exception.printStackTrace(); return 1; } @@ -474,28 +462,28 @@ public class ApplyTemplate extends ResourceWrapperActivity { publishProgress(true); } - BackupRestoreTool.RestoreConfig restore_config=new BackupRestoreTool.RestoreConfig(); + BackupRestoreTool.RestoreConfig restore_config = new BackupRestoreTool.RestoreConfig(); - restore_config.context=context; - restore_config.pathTo=mApplyMode==ApplyMode.REPLACE ? mAppBaseDir.getAbsolutePath() : mTemplateDir.getAbsolutePath(); + restore_config.context = context; + restore_config.pathTo = mApplyMode == ApplyMode.REPLACE ? mAppBaseDir.getAbsolutePath() : mTemplateDir.getAbsolutePath(); restore_config.isFrom = openTemplateStream(); - restore_config.restoreWidgetsData=true; - restore_config.restoreWallpaper=mLoadWallpaper; - restore_config.restoreFonts=true; + restore_config.restoreWidgetsData = true; + restore_config.restoreWallpaper = mLoadWallpaper; + restore_config.restoreFonts = true; - if(!BackupRestoreTool.restore(restore_config)) { - Utils.deleteDirectory(mTemplateDir, true); + if (!BackupRestoreTool.restore(restore_config)) { + Utils.deleteDirectory(mTemplateDir, true); return 2; } mEngineFrom.init(); - - if(mApplyMode == ApplyMode.MERGE) { + + if (mApplyMode == ApplyMode.MERGE) { // build the list of desktops to import recursively ArrayList desktopPages = new ArrayList(); for (int p : mEngineFrom.getPageManager().getAllPagesIds()) { - if(Page.isDashboard(p) && p != Page.APP_DRAWER_PAGE) { + if (Page.isDashboard(p) && p != Page.APP_DRAWER_PAGE) { // skip folders and the app drawer pages when merging desktopPages.add(mEngineFrom.getOrLoadPage(p)); } @@ -503,31 +491,31 @@ public class ApplyTemplate extends ResourceWrapperActivity { // do the grunt work of importing mTranslatedPageIds = mEngineTo.getPageManager().clonePages(desktopPages, true); - for(int i=0; i my_scripts = scriptManagerTo.getAllScriptMatching(Script.FLAG_ALL); - mTranslatedScriptIds = new SparseIntArray(); + mTranslatedScriptIds = new SparseIntArray(); ScriptManager scriptManagerFrom = mEngineFrom.getScriptManager(); ArrayList