()
val lastTargetUrl = AtomicReferenceNotNull("")
@@ -113,9 +113,61 @@ class NetworkTracker(
context.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE)
as ConnectivityManager
+ private lateinit var networkCallback : Any
+
init {
context.registerReceiver(this, IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION))
- context.registerReceiver(this, IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION))
+ if(Build.VERSION.SDK_INT >= 28) {
+ networkCallback = object : ConnectivityManager.NetworkCallback() {
+ override fun onCapabilitiesChanged(
+ network : Network?,
+ networkCapabilities : NetworkCapabilities?
+ ) {
+ super.onCapabilitiesChanged(network, networkCapabilities)
+ worker?.notifyEx()
+ }
+
+ override fun onLost(network : Network?) {
+ super.onLost(network)
+ worker?.notifyEx()
+ }
+
+ override fun onLinkPropertiesChanged(
+ network : Network?,
+ linkProperties : LinkProperties?
+ ) {
+ super.onLinkPropertiesChanged(network, linkProperties)
+ worker?.notifyEx()
+ }
+
+ override fun onUnavailable() {
+ super.onUnavailable()
+ worker?.notifyEx()
+ }
+
+ override fun onLosing(network : Network?, maxMsToLive : Int) {
+ super.onLosing(network, maxMsToLive)
+ worker?.notifyEx()
+ }
+
+ override fun onAvailable(network : Network?) {
+ super.onAvailable(network)
+ worker?.notifyEx()
+ }
+ }
+
+ (context.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager)
+ ?.registerNetworkCallback(
+ NetworkRequest.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .build()
+ , networkCallback as ConnectivityManager.NetworkCallback
+ )
+ } else {
+ @Suppress("DEPRECATION")
+ context.registerReceiver(this, IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION))
+ }
context.registerReceiver(this, IntentFilter(TETHER_STATE_CHANGED))
worker = Worker().apply {
start()
@@ -123,6 +175,10 @@ class NetworkTracker(
}
fun dispose() {
+ if(Build.VERSION.SDK_INT >= 28) {
+ (context.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager)
+ ?.unregisterNetworkCallback(networkCallback as ConnectivityManager.NetworkCallback)
+ }
context.unregisterReceiver(this)
worker?.cancel("disposed")
worker = null
@@ -155,9 +211,8 @@ class NetworkTracker(
if(intent.action == TETHER_STATE_CHANGED) {
val sb = StringBuilder("TETHER_STATE_CHANGED. ")
val extras = intent.extras
- for(key in extras.keySet()) {
- val v = extras[key]
- when(v) {
+ if(extras != null) for(key in extras.keySet()) {
+ when(val v = extras[key]) {
is ArrayList<*> -> sb.append("$key=[${v.joinToString("/")}],")
is Array<*> -> sb.append("$key=[${v.joinToString("/")}],")
else -> sb.append("$key=$v,")
@@ -291,8 +346,9 @@ class NetworkTracker(
// 種別ごとのネットワーク接続の状況
private class NetworkStatus(
- var type_name : String,
- var sub_name : String? = null,
+
+ val type_name : String,
+ val sub_name : String? = null,
var is_active : Boolean = false,
var strWifiStatus : String? = null
)
@@ -306,24 +362,54 @@ class NetworkTracker(
var other_active : String = ""
- fun addNetworkInfo(is_active : Boolean, ni : NetworkInfo?) {
- ni ?: return
+ @TargetApi(23)
+ fun addNetwork(nc : NetworkCapabilities?, is_active : Boolean) {
+ nc ?: return
- val is_wifi = ni.type == ConnectivityManager.TYPE_WIFI
+ val ns = NetworkStatus(
+ type_name = when {
+ nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> "WIFI"
+ nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI_AWARE) -> "WIFI_AWARE"
+ nc.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> "CELLULAR"
+ nc.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) -> "BLUETOOTH"
+ nc.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> "ETHERNET"
+ nc.hasTransport(NetworkCapabilities.TRANSPORT_VPN) -> "VPN"
+ nc.hasTransport(NetworkCapabilities.TRANSPORT_LOWPAN) -> "LOWPAN"
+ else -> "?"
+ },
+ sub_name = null,
+ is_active = is_active
+ )
- // Wi-Fiでもなく接続中でもないなら全くの無関係
- if(! is_wifi && ! ni.isConnected) return
+ // hasTransport は isConnectedを兼ねてるらしい
+ val wifiConnected = nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
+ if(wifiConnected) {
+ this.add(ns)
+ wifi_status = ns
+ } else if(is_active) {
+ this.add(ns)
+ other_active = ns.type_name
+ }
+ }
+
+ fun addNetworkInfo(ni : NetworkInfo?, is_active : Boolean) {
+ ni ?: return
+ @Suppress("DEPRECATION")
val ns = NetworkStatus(
type_name = ni.typeName,
sub_name = ni.subtypeName,
is_active = is_active
)
- this.add(ns)
+
+ @Suppress("DEPRECATION")
+ val is_wifi = ni.type == ConnectivityManager.TYPE_WIFI
if(is_wifi) {
+ this.add(ns)
wifi_status = ns
} else if(is_active) {
+ this.add(ns)
other_active = ns.type_name
}
}
@@ -465,7 +551,7 @@ class NetworkTracker(
var tester = testerMap[checkUrl]
if(tester?.isAlive == true) return
// log.v("${checkUrl}の確認を開始")
- tester = NetworkTracker.UrlTester(setting, log, targetUrl, checkUrl, onUrlTestComplete)
+ tester = UrlTester(setting, log, targetUrl, checkUrl, onUrlTestComplete)
testerMap[checkUrl] = tester
tester.start()
}
@@ -723,8 +809,12 @@ class NetworkTracker(
min(remain, 3000L)
} else try {
timeLastWiFiScan = now
- wifiManager.startScan()
- log.d(R.string.wifi_scan_start)
+ try {
+ log.d(R.string.wifi_scan_start)
+ @Suppress("DEPRECATION")
+ wifiManager.startScan()
+ } catch(ex : Throwable) {
+ }
3000L
} catch(ex : Throwable) {
log.trace(ex, "startScan() failed.")
@@ -783,33 +873,33 @@ class NetworkTracker(
// 現在のネットワーク接続を列挙する
if(Build.VERSION.SDK_INT >= 23) {
- var active_handle : Long? = null
- val an = connectivityManager.activeNetwork
- if(an != null) {
- active_handle = an.networkHandle
- }
- val src_list = connectivityManager.allNetworks
- if(src_list != null) {
- for(n in src_list) {
- val is_active =
- active_handle != null && active_handle == n.networkHandle
- val ni = connectivityManager.getNetworkInfo(n)
- ns_list.addNetworkInfo(is_active, ni)
+ val active_handle : Long? = connectivityManager.activeNetwork?.networkHandle
+
+ connectivityManager.allNetworks?.forEach { n ->
+ n ?: return@forEach
+ val isActive = active_handle?.equals(n.networkHandle) == true
+ if(Build.VERSION.SDK_INT >= 28) {
+ ns_list.addNetwork(
+ connectivityManager.getNetworkCapabilities(n),
+ isActive
+ )
+ } else {
+ ns_list.addNetworkInfo(
+ connectivityManager.getNetworkInfo(n),
+ isActive
+ )
}
}
+
} else {
- var active_name : String? = null
- val ani = connectivityManager.activeNetworkInfo
- if(ani != null) {
- active_name = ani.typeName
- }
@Suppress("DEPRECATION")
- val src_list = connectivityManager.allNetworkInfo
- if(src_list != null) {
- for(ni in src_list) {
- val is_active = active_name != null && active_name == ni.typeName
- ns_list.addNetworkInfo(is_active, ni)
- }
+ val active_name = connectivityManager.activeNetworkInfo?.typeName
+
+ @Suppress("DEPRECATION")
+ connectivityManager.allNetworkInfo?.forEach { ni ->
+ ni ?: return@forEach
+ val isActive = active_name?.equals(ni.typeName) == true
+ ns_list.addNetworkInfo(ni, isActive)
}
}
ns_list.afterAddAll()
@@ -871,7 +961,7 @@ class NetworkTracker(
while(! isCancelled) {
- val remain = try {
+ val remain = try {
checkNetwork()
} catch(ex : Throwable) {
log.trace(ex, "network check failed.")
@@ -897,7 +987,7 @@ class NetworkTracker(
}
logStatic.d("run: remain=$remain")
- waitEx(if(remain <= 0L) 5000L else if(remain > 10000L )10000L else remain)
+ waitEx(if(remain <= 0L) 5000L else if(remain > 10000L) 10000L else remain)
}
}
}
diff --git a/app/src/main/java/jp/juggler/fadownloader/util/HTTPClient.kt b/app/src/main/java/jp/juggler/fadownloader/util/HTTPClient.kt
index aaae9c3..8da0c96 100644
--- a/app/src/main/java/jp/juggler/fadownloader/util/HTTPClient.kt
+++ b/app/src/main/java/jp/juggler/fadownloader/util/HTTPClient.kt
@@ -139,11 +139,11 @@ class HTTPClient {
@Synchronized
fun cancel(log : LogWriter) {
val t = io_thread ?: return
- log.i( "[$caption,cancel] $t" )
+ log.i("[$caption,cancel] $t")
try {
t.interrupt()
} catch(ex : Throwable) {
- log.trace(ex,"cancel")
+ log.trace(ex, "cancel")
}
}
@@ -344,9 +344,9 @@ class HTTPClient {
)
if(! silent_error) {
- log.e( "[$caption,connect] $last_error")
+ log.e("[$caption,connect] $last_error")
if(ex.message == null) {
- log.trace(ex,"getHTTP")
+ log.trace(ex, "getHTTP")
}
}
this.rcode = - 1
@@ -356,9 +356,9 @@ class HTTPClient {
String.format("%s %s", ex.javaClass.simpleName, ex.message)
if(! silent_error) {
- log.e( "[$caption,connect] $last_error")
+ log.e("[$caption,connect] $last_error")
if(ex.message == null) {
- log.trace(ex,"getHTTP")
+ log.trace(ex, "getHTTP")
}
}
@@ -367,7 +367,7 @@ class HTTPClient {
if(ex is IOException
&& ex.message?.contains("authentication challenge") == true
) {
- log.trace(ex,"getHTTP")
+ log.trace(ex, "getHTTP")
log.d("Please check device's date and time.")
this.rcode = 401
return null
@@ -429,13 +429,13 @@ class HTTPClient {
}
} catch(ex : Throwable) {
last_error = String.format("%s %s", ex.javaClass.simpleName, ex.message)
- log.trace(ex,"getHTTP")
+ log.trace(ex, "getHTTP")
}
}
if(! silent_error) log.e("[%s] fail. try=%d. rcode=%d", caption, max_try, rcode)
} catch(ex : Throwable) {
- log.trace(ex,"getHTTP")
+ log.trace(ex, "getHTTP")
last_error = String.format("%s %s", ex.javaClass.simpleName, ex.message)
} finally {
synchronized(this) {
@@ -514,7 +514,7 @@ class HTTPClient {
}
} catch(ex : Throwable) {
- log.trace(ex,"get_cache")
+ log.trace(ex, "get_cache")
if(file.exists()) {
file.delete()
@@ -540,11 +540,11 @@ class HTTPClient {
}
// retry ?
} catch(ex : MalformedURLException) {
- log.trace(ex,"get_cache")
+ log.trace(ex, "get_cache")
last_error = String.format("bad URL:%s", ex.message)
break
} catch(ex : IOException) {
- log.trace(ex,"get_cache")
+ log.trace(ex, "get_cache")
last_error = String.format("%s %s", ex.javaClass.simpleName, ex.message)
}
@@ -637,7 +637,7 @@ class HTTPClient {
/// log.d("200: %s",file);
return file
} catch(ex : Throwable) {
- setError(log,ex)
+ setError(log, ex)
} finally {
try {
inStream?.close()
@@ -683,14 +683,14 @@ class HTTPClient {
// このエラーはリトライしてもムリ
break
} catch(ex : MalformedURLException) {
- setError(log,ex)
+ setError(log, ex)
break
} catch(ex : SocketTimeoutException) {
setError_silent(log, ex)
} catch(ex : ConnectException) {
setError_silent(log, ex)
} catch(ex : IOException) {
- setError(log,ex)
+ setError(log, ex)
}
}
@@ -705,8 +705,8 @@ class HTTPClient {
return false
}
- private fun setError(log:LogWriter,ex : Throwable) : Boolean {
- log.trace(ex,"setError")
+ private fun setError(log : LogWriter, ex : Throwable) : Boolean {
+ log.trace(ex, "setError")
rcode = 0
last_error = String.format("%s %s", ex.javaClass.simpleName, ex.message)
return false
@@ -728,9 +728,8 @@ class HTTPClient {
//! HTTPレスポンスのヘッダを読む
@Suppress("unused")
fun getHeaderInt(key : String, defVal : Int) : Int {
- val v = getHeaderString(key, null)
return try {
- Integer.parseInt(v, 10)
+ getHeaderString(key, null)?.toInt() ?: defVal
} catch(ex : Throwable) {
defVal
}
diff --git a/app/src/main/java/jp/juggler/fadownloader/util/PagerAdapterBase.kt b/app/src/main/java/jp/juggler/fadownloader/util/PagerAdapterBase.kt
index 57d1253..fa764db 100644
--- a/app/src/main/java/jp/juggler/fadownloader/util/PagerAdapterBase.kt
+++ b/app/src/main/java/jp/juggler/fadownloader/util/PagerAdapterBase.kt
@@ -1,7 +1,7 @@
package jp.juggler.fadownloader.util
import android.app.Activity
-import android.support.v4.view.PagerAdapter
+import androidx.viewpager.widget.PagerAdapter
import android.util.SparseArray
import android.view.LayoutInflater
import android.view.View
diff --git a/app/src/main/java/jp/juggler/fadownloader/util/PermissionChecker.kt b/app/src/main/java/jp/juggler/fadownloader/util/PermissionChecker.kt
index 5511946..43abb4f 100644
--- a/app/src/main/java/jp/juggler/fadownloader/util/PermissionChecker.kt
+++ b/app/src/main/java/jp/juggler/fadownloader/util/PermissionChecker.kt
@@ -4,7 +4,7 @@ import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
-import android.support.v4.content.ContextCompat
+import androidx.core.content.ContextCompat
import java.util.ArrayList
diff --git a/app/src/main/java/jp/juggler/fadownloader/util/Utils.kt b/app/src/main/java/jp/juggler/fadownloader/util/Utils.kt
index eaa9e23..0f6bf78 100644
--- a/app/src/main/java/jp/juggler/fadownloader/util/Utils.kt
+++ b/app/src/main/java/jp/juggler/fadownloader/util/Utils.kt
@@ -169,7 +169,7 @@ object Utils {
val e = z.length
while(i < e) {
val zc = z[i]
- taisaku_map[zc] = "" + Character.toString(h[i])
+ taisaku_map[zc] = "" + h[i].toString()
taisaku_map2.put(zc.toInt(), true)
++ i
}
@@ -312,25 +312,17 @@ object Utils {
return MIME_TYPE_APPLICATION_OCTET_STREAM
}
- internal class FileInfo(any_uri : String?) {
+ internal class FileInfo(any_uri : String) {
- var uri : Uri? = null
- var mime_type : String? = null
+ var uri : Uri = if(any_uri.startsWith("/")) {
+ Uri.fromFile(File(any_uri))
+ } else {
+ Uri.parse(any_uri)
+ }
- init {
- if(any_uri != null) {
- uri = if(any_uri.startsWith("/")) {
- Uri.fromFile(File(any_uri))
- } else {
- Uri.parse(any_uri)
- }
-
- val ext = MimeTypeMap.getFileExtensionFromUrl(any_uri)
- if(ext != null) {
- mime_type =
- MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext.toLowerCase())
- }
- }
+ var mime_type : String? = when(val ext = MimeTypeMap.getFileExtensionFromUrl(any_uri)) {
+ null -> null
+ else -> MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext.toLowerCase())
}
}
@@ -552,7 +544,8 @@ fun ByteArray.digestSHA256() : ByteArray {
return digest.digest(this)
}
-fun ByteArray.encodeBase64Safe() :String = Base64.encodeToString(this, Base64.URL_SAFE or Base64.NO_PADDING or Base64.NO_WRAP)
+fun ByteArray.encodeBase64Safe() :String =
+ Base64.encodeToString(this, Base64.URL_SAFE or Base64.NO_PADDING or Base64.NO_WRAP)
fun ByteArray.digestMD5() : String {
val md = MessageDigest.getInstance("MD5")
diff --git a/app/src/main/java/net/dinglisch/android/tasker/TaskerPlugin.java b/app/src/main/java/net/dinglisch/android/tasker/TaskerPlugin.java
index c1989ef..7847c51 100644
--- a/app/src/main/java/net/dinglisch/android/tasker/TaskerPlugin.java
+++ b/app/src/main/java/net/dinglisch/android/tasker/TaskerPlugin.java
@@ -51,169 +51,159 @@
import android.os.ResultReceiver;
import android.util.Log;
+@SuppressWarnings("unused")
public class TaskerPlugin {
- private final static String TAG = "TaskerPlugin";
+ private final static String TAG = "TaskerPlugin";
- private final static String BASE_KEY = "net.dinglisch.android.tasker";
+ private final static String BASE_KEY = "net.dinglisch.android.tasker";
- private final static String EXTRAS_PREFIX = BASE_KEY + ".extras.";
+ private final static String EXTRAS_PREFIX = BASE_KEY + ".extras.";
- private final static int FIRST_ON_FIRE_VARIABLES_TASKER_VERSION = 80;
+ private final static int FIRST_ON_FIRE_VARIABLES_TASKER_VERSION = 80;
- public final static String VARIABLE_PREFIX = "%";
+ public final static String VARIABLE_PREFIX = "%";
// when generating non-repeating integers, look this far back for repeats
// see getPositiveNonRepeatingRandomInteger()
- private final static int RANDOM_HISTORY_SIZE = 100;
+ private final static int RANDOM_HISTORY_SIZE = 100;
/**
- * Action that the EditActivity for an event plugin should be launched by
+ * Action that the EditActivity for an event plugin should be launched by
*/
- public final static String ACTION_EDIT_EVENT = BASE_KEY + ".ACTION_EDIT_EVENT";
+ public final static String ACTION_EDIT_EVENT = BASE_KEY + ".ACTION_EDIT_EVENT";
- private final static String VARIABLE_NAME_START_EXPRESSION = "[\\w&&[^_]]";
- private final static String VARIABLE_NAME_MID_EXPRESSION = "[\\w0-9]+";
- private final static String VARIABLE_NAME_END_EXPRESSION = "[\\w0-9&&[^_]]";
+ private final static String VARIABLE_NAME_START_EXPRESSION = "[\\w&&[^_]]";
+ private final static String VARIABLE_NAME_MID_EXPRESSION = "[\\w0-9]+";
+ private final static String VARIABLE_NAME_END_EXPRESSION = "[\\w0-9&&[^_]]";
- public final static String VARIABLE_NAME_MAIN_PART_MATCH_EXPRESSION =
- VARIABLE_NAME_START_EXPRESSION + VARIABLE_NAME_MID_EXPRESSION + VARIABLE_NAME_END_EXPRESSION
- ;
+ public final static String VARIABLE_NAME_MAIN_PART_MATCH_EXPRESSION =
+ VARIABLE_NAME_START_EXPRESSION + VARIABLE_NAME_MID_EXPRESSION + VARIABLE_NAME_END_EXPRESSION;
- public final static String VARIABLE_NAME_MATCH_EXPRESSION =
+ public final static String VARIABLE_NAME_MATCH_EXPRESSION =
VARIABLE_PREFIX + "+" +
- VARIABLE_NAME_MAIN_PART_MATCH_EXPRESSION
- ;
+ VARIABLE_NAME_MAIN_PART_MATCH_EXPRESSION;
- private static Pattern VARIABLE_NAME_MATCH_PATTERN = null;
+ private static Pattern VARIABLE_NAME_MATCH_PATTERN = null;
/**
- * @see #addVariableBundle(Bundle, Bundle)
- * @see Host#getVariablesBundle(Bundle)
+ * @see #addVariableBundle(Bundle, Bundle)
+ * @see Host#getVariablesBundle(Bundle)
*/
- private final static String EXTRA_VARIABLES_BUNDLE = EXTRAS_PREFIX + "VARIABLES";
+ private final static String EXTRA_VARIABLES_BUNDLE = EXTRAS_PREFIX + "VARIABLES";
/**
- * Host capabilities, passed to plugin with edit intents
+ * Host capabilities, passed to plugin with edit intents
*/
- private final static String EXTRA_HOST_CAPABILITIES = EXTRAS_PREFIX + "HOST_CAPABILITIES";
+ private final static String EXTRA_HOST_CAPABILITIES = EXTRAS_PREFIX + "HOST_CAPABILITIES";
/**
- * @see Setting#hostSupportsVariableReturn(Bundle)
+ * @see Setting#hostSupportsVariableReturn(Bundle)
*/
- public final static int EXTRA_HOST_CAPABILITY_SETTING_RETURN_VARIABLES = 2;
+ public final static int EXTRA_HOST_CAPABILITY_SETTING_RETURN_VARIABLES = 2;
/**
- * @see Condition#hostSupportsVariableReturn(Bundle)
+ * @see Condition#hostSupportsVariableReturn(Bundle)
*/
- public final static int EXTRA_HOST_CAPABILITY_CONDITION_RETURN_VARIABLES = 4;
+ public final static int EXTRA_HOST_CAPABILITY_CONDITION_RETURN_VARIABLES = 4;
/**
- * @see Setting#hostSupportsOnFireVariableReplacement(Bundle)
+ * @see Setting#hostSupportsOnFireVariableReplacement(Bundle)
*/
- public final static int EXTRA_HOST_CAPABILITY_SETTING_FIRE_VARIABLE_REPLACEMENT = 8;
+ public final static int EXTRA_HOST_CAPABILITY_SETTING_FIRE_VARIABLE_REPLACEMENT = 8;
/**
* @see Setting#hostSupportsVariableReturn(Bundle)
*/
- private final static int EXTRA_HOST_CAPABILITY_RELEVANT_VARIABLES = 16;
+ private final static int EXTRA_HOST_CAPABILITY_RELEVANT_VARIABLES = 16;
- public final static int EXTRA_HOST_CAPABILITY_SETTING_SYNCHRONOUS_EXECUTION = 32;
+ public final static int EXTRA_HOST_CAPABILITY_SETTING_SYNCHRONOUS_EXECUTION = 32;
- public final static int EXTRA_HOST_CAPABILITY_REQUEST_QUERY_DATA_PASS_THROUGH = 64;
+ public final static int EXTRA_HOST_CAPABILITY_REQUEST_QUERY_DATA_PASS_THROUGH = 64;
- public final static int EXTRA_HOST_CAPABILITY_ENCODING_JSON = 128;
+ public final static int EXTRA_HOST_CAPABILITY_ENCODING_JSON = 128;
- public final static int EXTRA_HOST_CAPABILITY_ALL =
+ public final static int EXTRA_HOST_CAPABILITY_ALL =
EXTRA_HOST_CAPABILITY_SETTING_RETURN_VARIABLES |
EXTRA_HOST_CAPABILITY_CONDITION_RETURN_VARIABLES |
EXTRA_HOST_CAPABILITY_SETTING_FIRE_VARIABLE_REPLACEMENT |
- EXTRA_HOST_CAPABILITY_RELEVANT_VARIABLES|
+ EXTRA_HOST_CAPABILITY_RELEVANT_VARIABLES |
EXTRA_HOST_CAPABILITY_SETTING_SYNCHRONOUS_EXECUTION |
EXTRA_HOST_CAPABILITY_REQUEST_QUERY_DATA_PASS_THROUGH |
- EXTRA_HOST_CAPABILITY_ENCODING_JSON
- ;
+ EXTRA_HOST_CAPABILITY_ENCODING_JSON;
/**
* Possible encodings of text in bundle values
*
- * @see #setKeyEncoding(Bundle,String[],Encoding)
+ * @see #setKeyEncoding(Bundle, String[], Encoding)
*/
- public enum Encoding { JSON };
+ public enum Encoding {JSON}
- private final static String BUNDLE_KEY_ENCODING_JSON_KEYS = BASE_KEY + ".JSON_ENCODED_KEYS";
+ private final static String BUNDLE_KEY_ENCODING_JSON_KEYS = BASE_KEY + ".JSON_ENCODED_KEYS";
- public static boolean hostSupportsKeyEncoding( Bundle extrasFromHost, Encoding encoding ) {
- switch ( encoding ) {
- case JSON:
- return hostSupports( extrasFromHost, EXTRA_HOST_CAPABILITY_ENCODING_JSON );
- default:
- return false;
- }
+ public static boolean hostSupportsKeyEncoding( Bundle extrasFromHost, Encoding encoding ){
+ return encoding == Encoding.JSON && hostSupports( extrasFromHost, EXTRA_HOST_CAPABILITY_ENCODING_JSON );
}
/**
+ * Miscellaneous operational hints going one way or the other
*
- * Miscellaneous operational hints going one way or the other
- * @see Setting#hostSupportsVariableReturn(Bundle)
+ * @see Setting#hostSupportsVariableReturn(Bundle)
*/
- private final static String EXTRA_HINTS_BUNDLE = EXTRAS_PREFIX + "HINTS";
+ private final static String EXTRA_HINTS_BUNDLE = EXTRAS_PREFIX + "HINTS";
- private final static String BUNDLE_KEY_HINT_PREFIX = ".hints.";
+ private final static String BUNDLE_KEY_HINT_PREFIX = ".hints.";
- private final static String BUNDLE_KEY_HINT_TIMEOUT_MS = BUNDLE_KEY_HINT_PREFIX + "TIMEOUT";
+ private final static String BUNDLE_KEY_HINT_TIMEOUT_MS = BUNDLE_KEY_HINT_PREFIX + "TIMEOUT";
/**
- *
- * @see #hostSupportsRelevantVariables(Bundle)
- * @see #addRelevantVariableList(Intent, String[])
- * @see #getRelevantVariableList(Bundle)
+ * @see #hostSupportsRelevantVariables(Bundle)
+ * @see #addRelevantVariableList(Intent, String[])
+ * @see #getRelevantVariableList(Bundle)
*/
- private final static String BUNDLE_KEY_RELEVANT_VARIABLES = BASE_KEY + ".RELEVANT_VARIABLES";
+ private final static String BUNDLE_KEY_RELEVANT_VARIABLES = BASE_KEY + ".RELEVANT_VARIABLES";
-
- public static boolean hostSupportsRelevantVariables( Bundle extrasFromHost ) {
- return hostSupports( extrasFromHost, EXTRA_HOST_CAPABILITY_RELEVANT_VARIABLES );
+ public static boolean hostSupportsRelevantVariables( Bundle extrasFromHost ){
+ return hostSupports( extrasFromHost, EXTRA_HOST_CAPABILITY_RELEVANT_VARIABLES );
}
/**
* Specifies to host which variables might be used by the plugin.
- *
+ *
* Used in EditActivity, before setResult().
*
- * @param intentToHost the intent being returned to the host
- * @param variableNames array of relevant variable names
+ * @param intentToHost the intent being returned to the host
+ * @param variableNames array of relevant variable names
*/
- public static void addRelevantVariableList( Intent intentToHost, String [] variableNames ) {
+ public static void addRelevantVariableList( Intent intentToHost, String[] variableNames ){
intentToHost.putExtra( BUNDLE_KEY_RELEVANT_VARIABLES, variableNames );
}
/**
* Validate a variable name.
- *
+ *
* The basic requirement for variables from a plugin is that they must be all lower-case.
*
- * @param varName name to check
+ * @param varName name to check
*/
- public static boolean variableNameValid( String varName ) {
+ public static boolean variableNameValid( String varName ){
boolean validFlag = false;
- if ( varName == null )
+ if( varName == null )
Log.d( TAG, "variableNameValid: null name" );
- else {
- if ( VARIABLE_NAME_MATCH_PATTERN == null )
+ else{
+ if( VARIABLE_NAME_MATCH_PATTERN == null )
VARIABLE_NAME_MATCH_PATTERN = Pattern.compile( VARIABLE_NAME_MATCH_EXPRESSION, 0 );
- if ( VARIABLE_NAME_MATCH_PATTERN.matcher( varName ).matches() ) {
+ if( VARIABLE_NAME_MATCH_PATTERN.matcher( varName ).matches() ){
- if ( variableNameIsLocal( varName ) )
+ if( variableNameIsLocal( varName ) )
validFlag = true;
else
Log.d( TAG, "variableNameValid: name not local: " + varName );
- }
- else
+ }else
Log.d( TAG, "variableNameValid: invalid name: " + varName );
}
@@ -225,24 +215,24 @@ public static boolean variableNameValid( String varName ) {
* The host may use this to e.g. show a variable selection list in it's UI.
* The host should use this if it previously indicated to the plugin that it supports relevant vars
*
- * @param fromHostIntentExtras usually from getIntent().getExtras()
+ * @param fromHostIntentExtras usually from getIntent().getExtras()
* @return variableNames an array of relevant variable names
*/
- public static String [] getRelevantVariableList( Bundle fromHostIntentExtras ) {
+ public static String[] getRelevantVariableList( Bundle fromHostIntentExtras ){
- String [] relevantVars = (String []) getBundleValueSafe( fromHostIntentExtras, BUNDLE_KEY_RELEVANT_VARIABLES, String [].class, "getRelevantVariableList" );
+ String[] relevantVars = (String[]) getBundleValueSafe( fromHostIntentExtras, BUNDLE_KEY_RELEVANT_VARIABLES, String[].class, "getRelevantVariableList" );
- if ( relevantVars == null )
- relevantVars = new String [0];
+ if( relevantVars == null )
+ relevantVars = new String[ 0 ];
return relevantVars;
}
/**
* Used by: plugin QueryReceiver, FireReceiver
- *
+ *
* Add a bundle of variable name/value pairs.
- *
+ *
* Names must be valid Tasker local variable names.
* Values must be String, String [] or ArrayList
* Null values cause deletion of possible already-existing variables
@@ -250,30 +240,30 @@ public static boolean variableNameValid( String varName ) {
* of any existing array indices (%arr1, %arr2 etc)
*
* @param resultExtras the result extras from the receiver onReceive (from a call to getResultExtras())
- * @param variables the variables to send
+ * @param variables the variables to send
* @see Setting#hostSupportsVariableReturn(Bundle)
* @see #variableNameValid(String)
*/
- public static void addVariableBundle( Bundle resultExtras, Bundle variables ) {
+ public static void addVariableBundle( Bundle resultExtras, Bundle variables ){
resultExtras.putBundle( EXTRA_VARIABLES_BUNDLE, variables );
}
/**
* Used by: plugin EditActivity
- *
+ *
* Specify the encoding for a set of bundle keys.
- *
+ *
* This is completely optional and currently only necessary if using Setting#setVariableReplaceKeys
* where the corresponding values of some of the keys specified are JSON encoded.
*
- * @param resultBundleToHost the bundle being returned to the host
- * @param keys the keys being returned to the host which are encoded in some way
- * @param encoding the encoding of the values corresponding to the specified keys
- * @see #setVariableReplaceKeys(Bundle,String[])
+ * @param resultBundleToHost the bundle being returned to the host
+ * @param keys the keys being returned to the host which are encoded in some way
+ * @param encoding the encoding of the values corresponding to the specified keys
+ * @see Setting#setVariableReplaceKeys(Bundle, String[])
* @see #hostSupportsKeyEncoding(Bundle, Encoding)
*/
- public static void setKeyEncoding( Bundle resultBundleToHost, String [] keys, Encoding encoding ) {
- if ( Encoding.JSON.equals( encoding ) )
+ public static void setKeyEncoding( Bundle resultBundleToHost, String[] keys, Encoding encoding ){
+ if( Encoding.JSON.equals( encoding ) )
addStringArrayToBundleAsString(
keys, resultBundleToHost, BUNDLE_KEY_ENCODING_JSON_KEYS, "setValueEncoding"
);
@@ -286,77 +276,75 @@ public static void setKeyEncoding( Bundle resultBundleToHost, String [] keys, En
public static class Setting {
/**
- * Variable name into which a description of any error that occurred can be placed
- * for the user to process.
- *
- * Should *only* be set when the BroadcastReceiver result code indicates a failure.
- *
- * Note that the user needs to have configured the task to continue after failure of the plugin
- * action otherwise they will not be able to make use of the error message.
- *
- * For use with #addRelevantVariableList(Intent, String[]) and #addVariableBundle(Bundle, Bundle)
- *
+ * Variable name into which a description of any error that occurred can be placed
+ * for the user to process.
+ *
+ * Should *only* be set when the BroadcastReceiver result code indicates a failure.
+ *
+ * Note that the user needs to have configured the task to continue after failure of the plugin
+ * action otherwise they will not be able to make use of the error message.
+ *
+ * For use with #addRelevantVariableList(Intent, String[]) and #addVariableBundle(Bundle, Bundle)
*/
- public final static String VARNAME_ERROR_MESSAGE = VARIABLE_PREFIX + "errmsg";
+ public final static String VARNAME_ERROR_MESSAGE = VARIABLE_PREFIX + "errmsg";
/**
- * @see #setVariableReplaceKeys(Bundle, String[])
+ * @see #setVariableReplaceKeys(Bundle, String[])
*/
- private final static String BUNDLE_KEY_VARIABLE_REPLACE_STRINGS = EXTRAS_PREFIX + "VARIABLE_REPLACE_KEYS";
+ private final static String BUNDLE_KEY_VARIABLE_REPLACE_STRINGS = EXTRAS_PREFIX + "VARIABLE_REPLACE_KEYS";
/**
- * @see #requestTimeoutMS(android.content.Intent, int)
+ * @see #requestTimeoutMS(android.content.Intent, int)
*/
- private final static String EXTRA_REQUESTED_TIMEOUT = EXTRAS_PREFIX + "REQUESTED_TIMEOUT";
+ private final static String EXTRA_REQUESTED_TIMEOUT = EXTRAS_PREFIX + "REQUESTED_TIMEOUT";
/**
- * @see #requestTimeoutMS(android.content.Intent, int)
+ * @see #requestTimeoutMS(android.content.Intent, int)
*/
- public final static int REQUESTED_TIMEOUT_MS_NONE = 0;
+ public final static int REQUESTED_TIMEOUT_MS_NONE = 0;
/**
- * @see #requestTimeoutMS(android.content.Intent, int)
+ * @see #requestTimeoutMS(android.content.Intent, int)
*/
- public final static int REQUESTED_TIMEOUT_MS_MAX = 3599000;
+ public final static int REQUESTED_TIMEOUT_MS_MAX = 3599000;
/**
- * @see #requestTimeoutMS(android.content.Intent, int)
+ * @see #requestTimeoutMS(android.content.Intent, int)
*/
- public final static int REQUESTED_TIMEOUT_MS_NEVER = REQUESTED_TIMEOUT_MS_MAX + 1000;
+ public final static int REQUESTED_TIMEOUT_MS_NEVER = REQUESTED_TIMEOUT_MS_MAX + 1000;
/**
- * @see #signalFinish(Context, Intent, int, Bundle)
- * @see #addCompletionIntent(Intent, Intent,ComponentName, boolean)
+ * @see #signalFinish(Context, Intent, int, Bundle)
+ * @see Host#addCompletionIntent(Intent, Intent, ComponentName, boolean)
*/
- private final static String EXTRA_PLUGIN_COMPLETION_INTENT = EXTRAS_PREFIX + "COMPLETION_INTENT";
+ private final static String EXTRA_PLUGIN_COMPLETION_INTENT = EXTRAS_PREFIX + "COMPLETION_INTENT";
/**
- * @see #signalFinish(Context, Intent, int, Bundle)
- * @see Host#getSettingResultCode(Intent)
+ * @see #signalFinish(Context, Intent, int, Bundle)
+ * @see Host#getSettingResultCode(Intent)
*/
- public final static String EXTRA_RESULT_CODE = EXTRAS_PREFIX + "RESULT_CODE";
+ public final static String EXTRA_RESULT_CODE = EXTRAS_PREFIX + "RESULT_CODE";
/**
- *
- * @see #signalFinish(Context, Intent, int, Bundle)
- * @see #addCompletionIntent(Intent, Intent,ComponentName, boolean)
+ * @see #signalFinish(Context, Intent, int, Bundle)
+ * @see Host##addCompletionIntent(Intent, Intent, ComponentName, boolean)
*/
public final static String EXTRA_CALL_SERVICE_PACKAGE = BASE_KEY + ".EXTRA_CALL_SERVICE_PACKAGE";
public final static String EXTRA_CALL_SERVICE = BASE_KEY + ".EXTRA_CALL_SERVICE";
public final static String EXTRA_CALL_SERVICE_FOREGROUND = BASE_KEY + ".EXTRA_CALL_SERVICE_FOREGROUND";
/**
- * @see #signalFinish(Context, Intent, int, Bundle)
- * @see Host#getSettingResultCode(Intent)
+ * @see #signalFinish(Context, Intent, int, Bundle)
+ * @see Host#getSettingResultCode(Intent)
*/
- public final static int RESULT_CODE_OK = Activity.RESULT_OK;
- public final static int RESULT_CODE_OK_MINOR_FAILURES = Activity.RESULT_FIRST_USER;
- public final static int RESULT_CODE_FAILED = Activity.RESULT_FIRST_USER + 1;
- public final static int RESULT_CODE_PENDING = Activity.RESULT_FIRST_USER + 2;
- public final static int RESULT_CODE_UNKNOWN = Activity.RESULT_FIRST_USER + 3;
+ public final static int RESULT_CODE_OK = Activity.RESULT_OK;
+ public final static int RESULT_CODE_OK_MINOR_FAILURES = Activity.RESULT_FIRST_USER;
+ public final static int RESULT_CODE_FAILED = Activity.RESULT_FIRST_USER + 1;
+ public final static int RESULT_CODE_PENDING = Activity.RESULT_FIRST_USER + 2;
+ public final static int RESULT_CODE_UNKNOWN = Activity.RESULT_FIRST_USER + 3;
/**
* If a plugin wants to define it's own error codes, start numbering them here.
@@ -364,46 +352,46 @@ public static class Setting {
* the user to process after the plugin action.
*/
- public final static int RESULT_CODE_FAILED_PLUGIN_FIRST = Activity.RESULT_FIRST_USER + 9;
+ public final static int RESULT_CODE_FAILED_PLUGIN_FIRST = Activity.RESULT_FIRST_USER + 9;
/**
* Used by: plugin EditActivity.
- *
+ *
* Indicates to plugin that host will replace variables in specified bundle keys.
- *
+ *
* Replacement takes place every time the setting is fired, before the bundle is
* passed to the plugin FireReceiver.
*
- * @param extrasFromHost intent extras from the intent received by the edit activity
+ * @param extrasFromHost intent extras from the intent received by the edit activity
* @see #setVariableReplaceKeys(Bundle, String[])
*/
- public static boolean hostSupportsOnFireVariableReplacement( Bundle extrasFromHost ) {
+ public static boolean hostSupportsOnFireVariableReplacement( Bundle extrasFromHost ){
return hostSupports( extrasFromHost, EXTRA_HOST_CAPABILITY_SETTING_FIRE_VARIABLE_REPLACEMENT );
}
/**
* Used by: plugin EditActivity.
- *
+ *
* Description as above.
- *
+ *
* This version also includes backwards compatibility with pre 4.2 Tasker versions.
* At some point this function will be deprecated.
*
- * @param editActivity the plugin edit activity, needed to test calling Tasker version
+ * @param editActivity the plugin edit activity, needed to test calling Tasker version
* @see #setVariableReplaceKeys(Bundle, String[])
*/
- public static boolean hostSupportsOnFireVariableReplacement( Activity editActivity ) {
+ public static boolean hostSupportsOnFireVariableReplacement( Activity editActivity ){
boolean supportedFlag = hostSupportsOnFireVariableReplacement( editActivity.getIntent().getExtras() );
- if ( ! supportedFlag ) {
+ if( ! supportedFlag ){
ComponentName callingActivity = editActivity.getCallingActivity();
- if ( callingActivity == null )
+ if( callingActivity == null )
Log.w( TAG, "hostSupportsOnFireVariableReplacement: null callingActivity, defaulting to false" );
- else {
+ else{
String callerPackage = callingActivity.getPackageName();
// Tasker only supporteed this from 1.0.10
@@ -417,32 +405,32 @@ public static boolean hostSupportsOnFireVariableReplacement( Activity editActivi
return supportedFlag;
}
- public static boolean hostSupportsSynchronousExecution( Bundle extrasFromHost ) {
+ public static boolean hostSupportsSynchronousExecution( Bundle extrasFromHost ){
return hostSupports( extrasFromHost, EXTRA_HOST_CAPABILITY_SETTING_SYNCHRONOUS_EXECUTION );
}
/**
* Request the host to wait the specified number of milliseconds before continuing.
* Note that the host may choose to ignore the request.
- *
+ *
* Maximum value is REQUESTED_TIMEOUT_MS_MAX.
* Also available are REQUESTED_TIMEOUT_MS_NONE (continue immediately without waiting
* for the plugin to finish) and REQUESTED_TIMEOUT_MS_NEVER (wait forever for
* a result).
- *
+ *
* Used in EditActivity, before setResult().
*
- * @param intentToHost the intent being returned to the host
- * @param timeoutMS
+ * @param intentToHost the intent being returned to the host
+ * @param timeoutMS
*/
- public static void requestTimeoutMS( Intent intentToHost, int timeoutMS ) {
- if ( timeoutMS < 0 )
+ public static void requestTimeoutMS( Intent intentToHost, int timeoutMS ){
+ if( timeoutMS < 0 )
Log.w( TAG, "requestTimeoutMS: ignoring negative timeout (" + timeoutMS + ")" );
- else {
- if (
+ else{
+ if(
( timeoutMS > REQUESTED_TIMEOUT_MS_MAX ) &&
( timeoutMS != REQUESTED_TIMEOUT_MS_NEVER )
- ) {
+ ){
Log.w( TAG, "requestTimeoutMS: requested timeout " + timeoutMS + " exceeds maximum, setting to max (" + REQUESTED_TIMEOUT_MS_MAX + ")" );
timeoutMS = REQUESTED_TIMEOUT_MS_MAX;
}
@@ -452,15 +440,15 @@ public static void requestTimeoutMS( Intent intentToHost, int timeoutMS ) {
/**
* Used by: plugin EditActivity
- *
+ *
* Indicates to host which bundle keys should be replaced.
*
- * @param resultBundleToHost the bundle being returned to the host
- * @param listOfKeyNames which bundle keys to replace variables in when setting fires
+ * @param resultBundleToHost the bundle being returned to the host
+ * @param listOfKeyNames which bundle keys to replace variables in when setting fires
* @see #hostSupportsOnFireVariableReplacement(Bundle)
- * @see #setKeyEncoding(Bundle,String[],Encoding)
+ * @see #setKeyEncoding(Bundle, String[], Encoding)
*/
- public static void setVariableReplaceKeys( Bundle resultBundleToHost, String [] listOfKeyNames ) {
+ public static void setVariableReplaceKeys( Bundle resultBundleToHost, String[] listOfKeyNames ){
addStringArrayToBundleAsString(
listOfKeyNames, resultBundleToHost, BUNDLE_KEY_VARIABLE_REPLACE_STRINGS,
"setVariableReplaceKeys"
@@ -469,29 +457,29 @@ public static void setVariableReplaceKeys( Bundle resultBundleToHost, String []
/**
* Used by: plugin FireReceiver
- *
+ *
* Indicates to plugin whether the host will process variables which it passes back
*
- * @param extrasFromHost intent extras from the intent received by the FireReceiver
+ * @param extrasFromHost intent extras from the intent received by the FireReceiver
* @see #signalFinish(Context, Intent, int, Bundle)
*/
- public static boolean hostSupportsVariableReturn( Bundle extrasFromHost ) {
+ public static boolean hostSupportsVariableReturn( Bundle extrasFromHost ){
return hostSupports( extrasFromHost, EXTRA_HOST_CAPABILITY_SETTING_RETURN_VARIABLES );
}
/**
* Used by: plugin FireReceiver
- *
+ *
* Tell the host that the plugin has finished execution.
- *
+ *
* This should only be used if RESULT_CODE_PENDING was returned by FireReceiver.onReceive().
*
* @param originalFireIntent the intent received from the host (via onReceive())
- * @param resultCode level of success in performing the settings
- * @param vars any variables that the plugin wants to set in the host
+ * @param resultCode level of success in performing the settings
+ * @param vars any variables that the plugin wants to set in the host
* @see #hostSupportsSynchronousExecution(Bundle)
*/
- public static boolean signalFinish( Context context, Intent originalFireIntent, int resultCode, Bundle vars ) {
+ public static boolean signalFinish( Context context, Intent originalFireIntent, int resultCode, Bundle vars ){
String errorPrefix = "signalFinish: ";
@@ -499,43 +487,42 @@ public static boolean signalFinish( Context context, Intent originalFireIntent,
String completionIntentString = (String) getExtraValueSafe( originalFireIntent, Setting.EXTRA_PLUGIN_COMPLETION_INTENT, String.class, "signalFinish" );
- if ( completionIntentString != null ) {
+ if( completionIntentString != null ){
Uri completionIntentUri = null;
- try {
+ try{
completionIntentUri = Uri.parse( completionIntentString );
}
// should only throw NullPointer but don't particularly trust it
- catch ( Exception e ) {
+ catch( Exception e ){
Log.w( TAG, errorPrefix + "couldn't parse " + completionIntentString );
}
- if ( completionIntentUri != null ) {
- try {
+ if( completionIntentUri != null ){
+ try{
Intent completionIntent = Intent.parseUri( completionIntentString, Intent.URI_INTENT_SCHEME );
completionIntent.putExtra( EXTRA_RESULT_CODE, resultCode );
- if ( vars != null )
+ if( vars != null )
completionIntent.putExtra( EXTRA_VARIABLES_BUNDLE, vars );
- String callServicePackage = (String) getExtraValueSafe(completionIntent, Setting.EXTRA_CALL_SERVICE_PACKAGE, String.class, "signalFinish");
- String callService = (String) getExtraValueSafe(completionIntent, Setting.EXTRA_CALL_SERVICE, String.class, "signalFinish");
- Boolean foreground = (Boolean) getExtraValueSafe(completionIntent, Setting.EXTRA_CALL_SERVICE_FOREGROUND, Boolean.class, "signalFinish");
- if (callServicePackage != null && callService != null && foreground != null) {
- completionIntent.setComponent(new ComponentName(callServicePackage, callService));
- if (foreground && android.os.Build.VERSION.SDK_INT >= 26) {
- context.startForegroundService(completionIntent);
- } else {
- context.startService(completionIntent);
+ String callServicePackage = (String) getExtraValueSafe( completionIntent, Setting.EXTRA_CALL_SERVICE_PACKAGE, String.class, "signalFinish" );
+ String callService = (String) getExtraValueSafe( completionIntent, Setting.EXTRA_CALL_SERVICE, String.class, "signalFinish" );
+ Boolean foreground = (Boolean) getExtraValueSafe( completionIntent, Setting.EXTRA_CALL_SERVICE_FOREGROUND, Boolean.class, "signalFinish" );
+ if( callServicePackage != null && callService != null && foreground != null ){
+ completionIntent.setComponent( new ComponentName( callServicePackage, callService ) );
+ if( foreground && android.os.Build.VERSION.SDK_INT >= 26 ){
+ context.startForegroundService( completionIntent );
+ }else{
+ context.startService( completionIntent );
}
- } else {
- context.sendBroadcast(completionIntent);
+ }else{
+ context.sendBroadcast( completionIntent );
}
okFlag = true;
- }
- catch ( URISyntaxException e ) {
+ }catch( URISyntaxException e ){
Log.w( TAG, errorPrefix + "bad URI: " + completionIntentUri );
}
}
@@ -549,22 +536,21 @@ public static boolean signalFinish( Context context, Intent originalFireIntent,
* Used by: plugin FireReceiver.
* Requires Tasker 4.7+
*
- * @param extrasFromHost intent extras from the intent received by the FireReceiver
+ * @param extrasFromHost intent extras from the intent received by the FireReceiver
* @return timeoutMS the hosts timeout setting for the action or -1 if no hint is available.
- *
- * @see #REQUESTED_TIMEOUT_MS_NONE, REQUESTED_TIMEOUT_MS_MAX, REQUESTED_TIMEOUT_MS_NEVER
+ * @see Setting#REQUESTED_TIMEOUT_MS_NONE, REQUESTED_TIMEOUT_MS_MAX, REQUESTED_TIMEOUT_MS_NEVER
*/
- public static int getHintTimeoutMS( Bundle extrasFromHost ) {
+ public static int getHintTimeoutMS( Bundle extrasFromHost ){
- int timeoutMS = -1;
+ int timeoutMS = - 1;
Bundle hintsBundle = (Bundle) TaskerPlugin.getBundleValueSafe( extrasFromHost, EXTRA_HINTS_BUNDLE, Bundle.class, "getHintTimeoutMS" );
- if ( hintsBundle != null ) {
+ if( hintsBundle != null ){
Integer val = (Integer) getBundleValueSafe( hintsBundle, BUNDLE_KEY_HINT_TIMEOUT_MS, Integer.class, "getHintTimeoutMS" );
- if ( val != null )
+ if( val != null )
timeoutMS = val;
}
@@ -580,23 +566,24 @@ public static class Condition {
* @see #getResultReceiver(Intent)
*/
public final static String EXTRA_RESULT_RECEIVER = BASE_KEY + ".EXTRA_RESULT_RECEIVER";
+
/**
* Used by: plugin QueryReceiver
- *
+ *
* Indicates to plugin whether the host will process variables which it passes back
*
- * @param extrasFromHost intent extras from the intent received by the QueryReceiver
+ * @param extrasFromHost intent extras from the intent received by the QueryReceiver
* @see #addVariableBundle(Bundle, Bundle)
*/
- public static boolean hostSupportsVariableReturn( Bundle extrasFromHost ) {
- return hostSupports( extrasFromHost, EXTRA_HOST_CAPABILITY_CONDITION_RETURN_VARIABLES );
+ public static boolean hostSupportsVariableReturn( Bundle extrasFromHost ){
+ return hostSupports( extrasFromHost, EXTRA_HOST_CAPABILITY_CONDITION_RETURN_VARIABLES );
}
- public static ResultReceiver getResultReceiver(Intent intentFromHost) {
- if (intentFromHost == null) {
+ public static ResultReceiver getResultReceiver( Intent intentFromHost ){
+ if( intentFromHost == null ){
return null;
}
- return (ResultReceiver) getExtraValueSafe(intentFromHost, EXTRA_RESULT_RECEIVER, ResultReceiver.class, "getResultReceiver");
+ return (ResultReceiver) getExtraValueSafe( intentFromHost, EXTRA_RESULT_RECEIVER, ResultReceiver.class, "getResultReceiver" );
}
}
@@ -605,47 +592,46 @@ public static ResultReceiver getResultReceiver(Intent intentFromHost) {
public static class Event {
- public final static String PASS_THROUGH_BUNDLE_MESSAGE_ID_KEY = BASE_KEY + ".MESSAGE_ID";
+ public final static String PASS_THROUGH_BUNDLE_MESSAGE_ID_KEY = BASE_KEY + ".MESSAGE_ID";
- private final static String EXTRA_REQUEST_QUERY_PASS_THROUGH_DATA = EXTRAS_PREFIX + "PASS_THROUGH_DATA";
+ private final static String EXTRA_REQUEST_QUERY_PASS_THROUGH_DATA = EXTRAS_PREFIX + "PASS_THROUGH_DATA";
/**
- * @param extrasFromHost intent extras from the intent received by the QueryReceiver
+ * @param extrasFromHost intent extras from the intent received by the QueryReceiver
* @see #addPassThroughData(Intent, Bundle)
*/
- public static boolean hostSupportsRequestQueryDataPassThrough( Bundle extrasFromHost ) {
- return hostSupports( extrasFromHost, EXTRA_HOST_CAPABILITY_REQUEST_QUERY_DATA_PASS_THROUGH );
+ public static boolean hostSupportsRequestQueryDataPassThrough( Bundle extrasFromHost ){
+ return hostSupports( extrasFromHost, EXTRA_HOST_CAPABILITY_REQUEST_QUERY_DATA_PASS_THROUGH );
}
/**
* Specify a bundle of data (probably representing whatever change happened in the condition)
* which will be included in the QUERY_CONDITION broadcast sent by the host for each
* event instance of the plugin.
- *
+ *
* The minimal purpose is to enable the plugin to associate a QUERY_CONDITION to the
* with the REQUEST_QUERY that caused it.
- *
+ *
* Note that for security reasons it is advisable to also store a message ID with the bundle
* which can be compared to known IDs on receipt. The host cannot validate the source of
* REQUEST_QUERY intents so fake data may be passed. Replay attacks are also possible.
* addPassThroughMesssageID() can be used to add an ID if the plugin doesn't wish to add it's
* own ID to the pass through bundle.
- *
+ *
* Note also that there are several situations where REQUEST_QUERY will not result in a
* QUERY_CONDITION intent (e.g. event throttling by the host), so plugin-local data
* indexed with a message ID needs to be timestamped and eventually timed-out.
- *
+ *
* This function can be called multiple times, each time all keys in data will be added to
* that of previous calls.
*
* @param requestQueryIntent intent being sent to the host
- * @param data the data to be passed-through
+ * @param data the data to be passed-through
* @see #hostSupportsRequestQueryDataPassThrough(Bundle)
* @see #retrievePassThroughData(Intent)
* @see #addPassThroughMessageID
- *
*/
- public static void addPassThroughData( Intent requestQueryIntent, Bundle data ) {
+ public static void addPassThroughData( Intent requestQueryIntent, Bundle data ){
Bundle passThroughBundle = retrieveOrCreatePassThroughBundle( requestQueryIntent );
@@ -655,16 +641,16 @@ public static void addPassThroughData( Intent requestQueryIntent, Bundle data )
/**
* Retrieve the pass through data from a QUERY_REQUEST from the host which was generated
* by a REQUEST_QUERY from the plugin.
- *
+ *
* Note that if addPassThroughMessageID() was previously called, the data will contain an extra
* key TaskerPlugin.Event.PASS_THOUGH_BUNDLE_MESSAGE_ID_KEY.
*
* @param queryConditionIntent QUERY_REQUEST sent from host
* @return data previously added to the REQUEST_QUERY intent
* @see #hostSupportsRequestQueryDataPassThrough(Bundle)
- * @see #addPassThroughData(Intent,Bundle)
+ * @see #addPassThroughData(Intent, Bundle)
*/
- public static Bundle retrievePassThroughData( Intent queryConditionIntent ) {
+ public static Bundle retrievePassThroughData( Intent queryConditionIntent ){
return (Bundle) getExtraValueSafe(
queryConditionIntent,
EXTRA_REQUEST_QUERY_PASS_THROUGH_DATA,
@@ -676,19 +662,17 @@ public static Bundle retrievePassThroughData( Intent queryConditionIntent ) {
/**
* Add a message ID to a REQUEST_QUERY intent which will then be included in the corresponding
* QUERY_CONDITION broadcast sent by the host for each event instance of the plugin.
- *
+ *
* The minimal purpose is to enable the plugin to associate a QUERY_CONDITION to the
* with the REQUEST_QUERY that caused it. It also allows the message to be verified
* by the plugin to prevent e.g. replay attacks
*
* @param requestQueryIntent intent being sent to the host
- * @return a guaranteed non-repeating within 100 calls message ID
+ * @return an ID for the bundle so it can be identified and the caller verified when it is again received by the plugin
* @see #hostSupportsRequestQueryDataPassThrough(Bundle)
* @see #retrievePassThroughData(Intent)
- * @return an ID for the bundle so it can be identified and the caller verified when it is again received by the plugin
- *
*/
- public static int addPassThroughMessageID( Intent requestQueryIntent ) {
+ public static int addPassThroughMessageID( Intent requestQueryIntent ){
Bundle passThroughBundle = retrieveOrCreatePassThroughBundle( requestQueryIntent );
@@ -708,13 +692,13 @@ public static int addPassThroughMessageID( Intent requestQueryIntent ) {
* @see #hostSupportsRequestQueryDataPassThrough(Bundle)
* @see #addPassThroughData(Intent,Bundle)
*/
- public static int retrievePassThroughMessageID( Intent queryConditionIntent ) {
+ public static int retrievePassThroughMessageID( Intent queryConditionIntent ){
- int toReturn = -1;
+ int toReturn = - 1;
Bundle passThroughData = Event.retrievePassThroughData( queryConditionIntent );
- if ( passThroughData != null ) {
+ if( passThroughData != null ){
Integer id = (Integer) getBundleValueSafe(
passThroughData,
PASS_THROUGH_BUNDLE_MESSAGE_ID_KEY,
@@ -722,7 +706,7 @@ public static int retrievePassThroughMessageID( Intent queryConditionIntent ) {
"retrievePassThroughMessageID"
);
- if ( id != null )
+ if( id != null )
toReturn = id;
}
@@ -730,13 +714,13 @@ public static int retrievePassThroughMessageID( Intent queryConditionIntent ) {
}
// internal use
- private static Bundle retrieveOrCreatePassThroughBundle( Intent requestQueryIntent ) {
+ private static Bundle retrieveOrCreatePassThroughBundle( Intent requestQueryIntent ){
Bundle passThroughBundle;
- if ( requestQueryIntent.hasExtra( EXTRA_REQUEST_QUERY_PASS_THROUGH_DATA ) )
+ if( requestQueryIntent.hasExtra( EXTRA_REQUEST_QUERY_PASS_THROUGH_DATA ) )
passThroughBundle = requestQueryIntent.getBundleExtra( EXTRA_REQUEST_QUERY_PASS_THROUGH_DATA );
- else {
+ else{
passThroughBundle = new Bundle();
requestQueryIntent.putExtra( EXTRA_REQUEST_QUERY_PASS_THROUGH_DATA, passThroughBundle );
}
@@ -752,30 +736,30 @@ public static class Host {
* Tell the plugin what capabilities the host support. This should be called when sending
* intents to any EditActivity, FireReceiver or QueryReceiver.
*
- * @param toPlugin the intent we're sending
+ * @param toPlugin the intent we're sending
* @return capabilities one or more of the EXTRA_HOST_CAPABILITY_XXX flags
*/
- public static Intent addCapabilities( Intent toPlugin, int capabilities ) {
- return toPlugin.putExtra( EXTRA_HOST_CAPABILITIES, capabilities );
+ public static Intent addCapabilities( Intent toPlugin, int capabilities ){
+ return toPlugin.putExtra( EXTRA_HOST_CAPABILITIES, capabilities );
}
/**
* Add an intent to the fire intent before it goes to the plugin FireReceiver, which the plugin
* can use to signal when it is finished. Only use if @code{pluginWantsSychronousExecution} is true.
*
- * @param fireIntent fire intent going to the plugin
+ * @param fireIntent fire intent going to the plugin
* @param completionIntent intent which will signal the host that the plugin is finished.
- * Implementation is host-dependent.
+ * Implementation is host-dependent.
*/
- public static void addCompletionIntent(Intent fireIntent, Intent completionIntent, ComponentName callService, boolean foreground) {
- if (callService != null) {
- completionIntent.putExtra(Setting.EXTRA_CALL_SERVICE_PACKAGE, callService.getPackageName());
- completionIntent.putExtra(Setting.EXTRA_CALL_SERVICE, callService.getClassName());
- completionIntent.putExtra(Setting.EXTRA_CALL_SERVICE_FOREGROUND, foreground);
+ public static void addCompletionIntent( Intent fireIntent, Intent completionIntent, ComponentName callService, boolean foreground ){
+ if( callService != null ){
+ completionIntent.putExtra( Setting.EXTRA_CALL_SERVICE_PACKAGE, callService.getPackageName() );
+ completionIntent.putExtra( Setting.EXTRA_CALL_SERVICE, callService.getClassName() );
+ completionIntent.putExtra( Setting.EXTRA_CALL_SERVICE_FOREGROUND, foreground );
}
fireIntent.putExtra(
Setting.EXTRA_PLUGIN_COMPLETION_INTENT,
- completionIntent.toUri(Intent.URI_INTENT_SCHEME)
+ completionIntent.toUri( Intent.URI_INTENT_SCHEME )
);
}
@@ -786,7 +770,7 @@ public static void addCompletionIntent(Intent fireIntent, Intent completionInten
* @param completionIntent intent returned from the plugin when it finished.
* @return resultCode measure of plugin success, defaults to UNKNOWN
*/
- public static int getSettingResultCode( Intent completionIntent ) {
+ public static int getSettingResultCode( Intent completionIntent ){
Integer val = (Integer) getExtraValueSafe( completionIntent, Setting.EXTRA_RESULT_CODE, Integer.class, "getSettingResultCode" );
@@ -803,7 +787,7 @@ public static int getSettingResultCode( Intent completionIntent ) {
* @see #addCapabilities(Intent, int)
*/
- public static Bundle getVariablesBundle( Bundle resultExtras ) {
+ public static Bundle getVariablesBundle( Bundle resultExtras ){
return (Bundle) getBundleValueSafe(
resultExtras, EXTRA_VARIABLES_BUNDLE, Bundle.class, "getVariablesBundle"
);
@@ -812,20 +796,20 @@ public static Bundle getVariablesBundle( Bundle resultExtras ) {
/**
* Inform a setting plugin of the timeout value the host is using.
*
- * @param toPlugin the intent we're sending
+ * @param toPlugin the intent we're sending
* @param timeoutMS the hosts timeout setting for the action. Note that this may differ from
- * that which the plugin requests.
- * @see #REQUESTED_TIMEOUT_MS_NONE, REQUESTED_TIMEOUT_MS_MAX, REQUESTED_TIMEOUT_MS_NEVER
+ * that which the plugin requests.
+ * @see Setting#REQUESTED_TIMEOUT_MS_NONE, REQUESTED_TIMEOUT_MS_MAX, REQUESTED_TIMEOUT_MS_NEVER
*/
- public static void addHintTimeoutMS( Intent toPlugin, int timeoutMS ) {
+ public static void addHintTimeoutMS( Intent toPlugin, int timeoutMS ){
getHintsBundle( toPlugin, "addHintTimeoutMS" ).putInt( BUNDLE_KEY_HINT_TIMEOUT_MS, timeoutMS );
}
- private static Bundle getHintsBundle( Intent intent, String funcName ) {
+ private static Bundle getHintsBundle( Intent intent, String funcName ){
Bundle hintsBundle = (Bundle) getExtraValueSafe( intent, EXTRA_HINTS_BUNDLE, Bundle.class, funcName );
- if ( hintsBundle == null ) {
+ if( hintsBundle == null ){
hintsBundle = new Bundle();
intent.putExtra( EXTRA_HINTS_BUNDLE, hintsBundle );
}
@@ -833,30 +817,30 @@ private static Bundle getHintsBundle( Intent intent, String funcName ) {
return hintsBundle;
}
- public static boolean haveRequestedTimeout( Bundle extrasFromPluginEditActivity ) {
+ public static boolean haveRequestedTimeout( Bundle extrasFromPluginEditActivity ){
return extrasFromPluginEditActivity.containsKey( Setting.EXTRA_REQUESTED_TIMEOUT );
}
- public static int getRequestedTimeoutMS( Bundle extrasFromPluginEditActivity ) {
+ public static int getRequestedTimeoutMS( Bundle extrasFromPluginEditActivity ){
return
(Integer) getBundleValueSafe(
- extrasFromPluginEditActivity, Setting.EXTRA_REQUESTED_TIMEOUT, Integer.class, "getRequestedTimeout"
+ extrasFromPluginEditActivity, Setting.EXTRA_REQUESTED_TIMEOUT, Integer.class, "getRequestedTimeout"
)
;
}
- public static String [] getSettingVariableReplaceKeys( Bundle fromPluginEditActivity ) {
+ public static String[] getSettingVariableReplaceKeys( Bundle fromPluginEditActivity ){
return getStringArrayFromBundleString(
fromPluginEditActivity, Setting.BUNDLE_KEY_VARIABLE_REPLACE_STRINGS,
"getSettingVariableReplaceKeys"
);
}
- public static String [] getKeysWithEncoding( Bundle fromPluginEditActivity, Encoding encoding ) {
+ public static String[] getKeysWithEncoding( Bundle fromPluginEditActivity, Encoding encoding ){
- String [] toReturn = null;
+ String[] toReturn = null;
- if ( Encoding.JSON.equals( encoding ) )
+ if( Encoding.JSON.equals( encoding ) )
toReturn = getStringArrayFromBundleString(
fromPluginEditActivity, TaskerPlugin.BUNDLE_KEY_ENCODING_JSON_KEYS,
"getKeyEncoding:JSON"
@@ -867,39 +851,39 @@ public static int getRequestedTimeoutMS( Bundle extrasFromPluginEditActivity ) {
return toReturn;
}
- public static boolean haveRelevantVariables( Bundle b ) {
+ public static boolean haveRelevantVariables( Bundle b ){
return b.containsKey( BUNDLE_KEY_RELEVANT_VARIABLES );
}
- public static void cleanRelevantVariables( Bundle b ) {
+ public static void cleanRelevantVariables( Bundle b ){
b.remove( BUNDLE_KEY_RELEVANT_VARIABLES );
}
- public static void cleanHints( Bundle extras ) {
+ public static void cleanHints( Bundle extras ){
extras.remove( TaskerPlugin.EXTRA_HINTS_BUNDLE );
}
- public static void cleanRequestedTimeout( Bundle extras ) {
+ public static void cleanRequestedTimeout( Bundle extras ){
extras.remove( Setting.EXTRA_REQUESTED_TIMEOUT );
}
- public static void cleanSettingReplaceVariables( Bundle b ) {
+ public static void cleanSettingReplaceVariables( Bundle b ){
b.remove( Setting.BUNDLE_KEY_VARIABLE_REPLACE_STRINGS );
}
}
// ---------------------------------- HELPER FUNCTIONS -------------------------------- //
- private static Object getBundleValueSafe( Bundle b, String key, Class> expectedClass, String funcName ) {
+ private static Object getBundleValueSafe( Bundle b, String key, Class< ? > expectedClass, String funcName ){
Object value = null;
- if ( b != null ) {
- if ( b.containsKey( key ) ) {
+ if( b != null ){
+ if( b.containsKey( key ) ){
Object obj = b.get( key );
- if ( obj == null )
+ if( obj == null )
Log.w( TAG, funcName + ": " + key + ": null value" );
- else if ( obj.getClass() != expectedClass )
- Log.w( TAG, funcName + ": " + key + ": expected " + expectedClass.getClass().getName() + ", got " + obj.getClass().getName() );
+ else if( obj.getClass() != expectedClass )
+ Log.w( TAG, funcName + ": " + key + ": expected " + expectedClass.getName() + ", got " + obj.getClass().getName() );
else
value = obj;
}
@@ -907,13 +891,13 @@ else if ( obj.getClass() != expectedClass )
return value;
}
- private static Object getExtraValueSafe( Intent i, String key, Class> expectedClass, String funcName ) {
+ private static Object getExtraValueSafe( Intent i, String key, Class< ? > expectedClass, String funcName ){
return ( i.hasExtra( key ) ) ?
getBundleValueSafe( i.getExtras(), key, expectedClass, funcName ) :
null;
}
- private static boolean hostSupports( Bundle extrasFromHost, int capabilityFlag ) {
+ private static boolean hostSupports( Bundle extrasFromHost, int capabilityFlag ){
Integer flags = (Integer) getBundleValueSafe( extrasFromHost, EXTRA_HOST_CAPABILITIES, Integer.class, "hostSupports" );
return
( flags != null ) &&
@@ -921,17 +905,16 @@ private static boolean hostSupports( Bundle extrasFromHost, int capabilityFlag )
;
}
- public static int getPackageVersionCode( PackageManager pm, String packageName ) {
+ public static int getPackageVersionCode( PackageManager pm, String packageName ){
- int code = -1;
+ int code = - 1;
- if ( pm != null ) {
- try {
+ if( pm != null ){
+ try{
PackageInfo pi = pm.getPackageInfo( packageName, 0 );
- if ( pi != null )
+ if( pi != null )
code = pi.versionCode;
- }
- catch ( Exception e ) {
+ }catch( Exception e ){
Log.e( TAG, "getPackageVersionCode: exception getting package info" );
}
}
@@ -939,64 +922,61 @@ public static int getPackageVersionCode( PackageManager pm, String packageName )
return code;
}
- private static boolean variableNameIsLocal( String varName ) {
+ private static boolean variableNameIsLocal( String varName ){
int digitCount = 0;
int length = varName.length();
- for ( int x = 0; x < length; x++ ) {
+ for( int x = 0 ; x < length ; x++ ){
char ch = varName.charAt( x );
- if ( Character.isUpperCase( ch ) )
+ if( Character.isUpperCase( ch ) )
return false;
- else if ( Character.isDigit( ch ) )
+ else if( Character.isDigit( ch ) )
digitCount++;
}
- if ( digitCount == ( varName.length() - 1 ) )
- return false;
-
- return true;
+ return digitCount != ( varName.length() - 1 );
}
- private static String [] getStringArrayFromBundleString( Bundle bundle, String key, String funcName ) {
+ private static String[] getStringArrayFromBundleString( Bundle bundle, String key, String funcName ){
String spec = (String) getBundleValueSafe( bundle, key, String.class, funcName );
- String [] toReturn = null;
+ String[] toReturn = null;
- if ( spec != null )
+ if( spec != null )
toReturn = spec.split( " " );
return toReturn;
}
- private static void addStringArrayToBundleAsString( String [] toAdd, Bundle bundle, String key, String callerName ) {
+ private static void addStringArrayToBundleAsString( String[] toAdd, Bundle bundle, String key, String callerName ){
StringBuilder builder = new StringBuilder();
- if ( toAdd != null ) {
+ if( toAdd != null ){
- for ( String keyName : toAdd ) {
+ for( String keyName : toAdd ){
- if ( keyName.contains( " " ) )
+ if( keyName.contains( " " ) )
Log.w( TAG, callerName + ": ignoring bad keyName containing space: " + keyName );
- else {
- if ( builder.length() > 0 )
+ else{
+ if( builder.length() > 0 )
builder.append( ' ' );
builder.append( keyName );
}
- if ( builder.length() > 0 )
+ if( builder.length() > 0 )
bundle.putString( key, builder.toString() );
}
}
}
// state tracking for random number sequence
- private static int [] lastRandomsSeen = null;
- private static int randomInsertPointer = 0;
+ private static int[] lastRandomsSeen = null;
+ private static int randomInsertPointer = 0;
private static SecureRandom sr = null;
/**
@@ -1005,34 +985,34 @@ private static void addStringArrayToBundleAsString( String [] toAdd, Bundle bund
*
* @return a random positive integer
*/
- public static int getPositiveNonRepeatingRandomInteger() {
+ public static int getPositiveNonRepeatingRandomInteger(){
// initialize on first call
- if ( sr == null ) {
+ if( sr == null ){
sr = new SecureRandom();
- lastRandomsSeen = new int[RANDOM_HISTORY_SIZE];
+ lastRandomsSeen = new int[ RANDOM_HISTORY_SIZE ];
- for ( int x = 0; x < lastRandomsSeen.length; x++ )
- lastRandomsSeen[x] = -1;
+ for( int x = 0 ; x < lastRandomsSeen.length ; x++ )
+ lastRandomsSeen[ x ] = - 1;
}
int toReturn;
- do {
+ do{
// pick a number
toReturn = sr.nextInt( Integer.MAX_VALUE );
// check we havn't see it recently
- for ( int seen : lastRandomsSeen ) {
- if ( seen == toReturn ) {
- toReturn = -1;
+ for( int seen : lastRandomsSeen ){
+ if( seen == toReturn ){
+ toReturn = - 1;
break;
}
}
}
- while ( toReturn == -1 );
+ while( toReturn == - 1 );
// update history
- lastRandomsSeen[randomInsertPointer] = toReturn;
+ lastRandomsSeen[ randomInsertPointer ] = toReturn;
randomInsertPointer = ( randomInsertPointer + 1 ) % lastRandomsSeen.length;
return toReturn;
diff --git a/app/src/main/res/layout/act_main.xml b/app/src/main/res/layout/act_main.xml
index f1eec70..9653fc9 100644
--- a/app/src/main/res/layout/act_main.xml
+++ b/app/src/main/res/layout/act_main.xml
@@ -113,14 +113,14 @@
android:textColor="#FFF"
/>
-
-
-
+
diff --git a/app/src/main/res/layout/page_setting.xml b/app/src/main/res/layout/page_setting.xml
index 03a6e73..66b2b66 100644
--- a/app/src/main/res/layout/page_setting.xml
+++ b/app/src/main/res/layout/page_setting.xml
@@ -438,6 +438,12 @@
/>
+
+
テザリングモードでは、このアプリはデバイスへのHTTP接続をテストします。しかしこのテストは通信状況などの理由により待たされた挙句失敗する場合があります。\nそのタイムアウトをこの設定で変更できます。単位は秒数、デフォルトは15です。
Wi-Fiスキャン間隔 (Wi-Fi AP半強制時)
- Wi-Fi AP半強制モードでは、指定されたAPが過去のWi-Fiスキャン結果に含まれない場合にこのアプリは定期的にWi-Fiスキャンの開始を行います。\nしかし頻繁なWi-Fiスキャンは端末のバッテリーを浪費します。\nその時間間隔をこの設定で変更できます。単位は秒数、デフォルトは10です。
+ Wi-Fi AP半強制モードでは、指定されたAPが過去のWi-Fiスキャン結果に含まれない場合にこのアプリは定期的にWi-Fiスキャンの開始を行います。\nしかし頻繁なWi-Fiスキャンは端末のバッテリーを浪費します。\nその時間間隔をこの設定で変更できます。単位は秒数、デフォルトは10です。
+\n\n*制限*
+\nWifiManager.startScan()を使用したスキャンの頻度には、次の制限が適用されます。
+\n・Android 8.x: 各バックグラウンドアプリは、30分間に1回スキャンできます。
+\n・Android 9: 各フォアグラウンドアプリは、2分間に4回スキャンできます。 すべてのバックグラウンドアプリは合計で30分間に1回スキャンできます。
+\n・Android 10+: Android 9と同じ制限が適用されます。開発者オプションで制限を無効にできます。開発者オプション/ネットワーク/Wi-Fiスキャン調整
+
+ Android 8以降はWi-Fiスキャンの周期に制限があります。(\"?\"を参照)
Wi-Fi AP変更間隔
Wi-Fi AP半強制モードでは、指定されたAPがスキャン結果に含まれるが選択されていない場合にこのアプリは定期的にW-Fi APの変更を試みます。\nその時間間隔をこの設定で変更できます。単位は秒数、デフォルトは5です。
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 2b08238..1149853 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -224,7 +224,14 @@ FADownloaderはテザリング内部のLANにUDPパケットをばらまいた
In tethering mode, this app test HTTP connection to detected device. but sometimes this test will failed by socket timeout.\nThis setting can change its timeouts.\nUnit is seconds, default is 15.
Wi-Fi scan interval (force Wi-Fi AP mode)
- In force Wi-Fi AP mode, this app starts Wi-Fi scan to detect target AP if it\'s is not found in previous scan result.\nBut frequently Wi-Fi scan wastes battery.\nThis setting can change its intervals.\nUnit is seconds, default is 10.
+ In force Wi-Fi AP mode, this app starts Wi-Fi scan to detect target AP if it\'s is not found in previous scan result.\nBut frequently Wi-Fi scan wastes battery.\nThis setting can change its intervals.\nUnit is seconds, default is 10.
+\n\n*Throttling*
+\nThe following limitations apply to the frequency of scans using WifiManager.startScan().
+\n・Android 8.x: Each background app can scan one time in a 30-minute period.
+\n・Android 9: Each foreground app can scan four times in a 2-minute period. All background apps combined can scan one time in a 30-minute period.
+\n・Android 10+: The same throttling limits from Android 9 apply. There is a new developer option to toggle the throttling off for local testing (under Developer Options > Networking > Wi-Fi scan throttling).
+
+ Android 8 or later have limitation about wifi scan frequency. (see \"?\")
Wi-Fi change AP interval (force Wi-Fi AP mode)
In force Wi-Fi AP mode, this app change Wi-Fi AP to target AP if it\'s is found in scan result, but it\'s not selected.\nThis setting can change its intervals.\nUnit is seconds, default is 5.
diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml
new file mode 100644
index 0000000..b7ced7d
--- /dev/null
+++ b/app/src/main/res/xml/network_security_config.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/billing/build.gradle b/billing/build.gradle
index 8a6bae5..99db9fa 100644
--- a/billing/build.gradle
+++ b/billing/build.gradle
@@ -9,7 +9,7 @@ android {
versionCode 1
versionName "1.0"
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
@@ -23,10 +23,11 @@ android {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
- androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
+ androidTestImplementation 'androidx.test.ext:junit:1.1.1'
+ androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0', {
exclude group: 'com.android.support', module: 'support-annotations'
})
testImplementation 'junit:junit:4.12'
- implementation "com.android.support:appcompat-v7:$asl_version"
+ implementation 'androidx.appcompat:appcompat:1.1.0'
}
diff --git a/billing/src/main/java/com/example/android/trivialdrivesample/util/Base64.java b/billing/src/main/java/com/example/android/trivialdrivesample/util/Base64.java
index 4d224ba..51b1808 100644
--- a/billing/src/main/java/com/example/android/trivialdrivesample/util/Base64.java
+++ b/billing/src/main/java/com/example/android/trivialdrivesample/util/Base64.java
@@ -31,540 +31,551 @@
* @version 1.3
*/
+import android.annotation.SuppressLint;
+
/**
* Base64 converter class. This code is not a complete MIME encoder;
* it simply converts binary data to base64 data and back.
*
- *
Note {@link CharBase64} is a GWT-compatible implementation of this
+ *
Note CharBase64 is a GWT-compatible implementation of this
* class.
*/
-public class Base64 {
- /** Specify encoding (value is {@code true}). */
- public final static boolean ENCODE = true;
-
- /** 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 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 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 */
- };
-
- /** 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;
-
- /** 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 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 && outLen > 0) {
- if (outBuff[outLen - 1] != '=') {
- break;
- }
- outLen -= 1;
- }
-
- return new String(outBuff, 0, outLen);
- }
-
- /**
- * 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;
- }
-
-
- /* ******** 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
- * @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");
- }
- 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;
- }
+@SuppressWarnings("unused") public class Base64 {
+ /**
+ * Specify encoding (value is {@code true}).
+ */
+ public final static boolean ENCODE = true;
+
+ /**
+ * 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 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 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 */
+ };
+
+ /**
+ * 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;
+
+ /**
+ * 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 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 && outLen > 0 ){
+ if( outBuff[ outLen - 1 ] != '=' ){
+ break;
+ }
+ outLen -= 1;
+ }
+
+ return new String( outBuff, 0, outLen );
+ }
+
+ /**
+ * 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
+ */
+ @SuppressLint("Assert")
+ 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;
+ }
+
+
+ /* ******** 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;
+ byte sbiCrop;
+ byte sbiDecode;
+ 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 ){
+ 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/build.gradle b/build.gradle
index 9bda7ab..39b912c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -2,14 +2,15 @@
buildscript {
- ext.kotlin_version = '1.2.70'
- ext.kotlinx_coroutines_version = '0.25.3'
- ext.anko_version = '0.10.5'
+ ext.kotlin_version = '1.3.50'
+ ext.kotlinx_coroutines_version = '1.3.1'
+ ext.anko_version = '0.10.8'
// Google Api の play-services-location が更新されないとASLのバージョンを上げられない
- ext.min_sdk_version = 15
- ext.target_sdk_version = 26
- ext.asl_version = '26.1.0'
+ ext.min_sdk_version = 16
+ ext.target_sdk_version = 28
+ ext.appcompat_version='1.1.0'
+ ext.asl_version = '28.0.0'
repositories {
jcenter()
@@ -21,8 +22,8 @@ buildscript {
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.1.4'
- classpath 'com.google.gms:google-services:4.1.0'
+ classpath 'com.android.tools.build:gradle:3.5.1'
+ classpath 'com.google.gms:google-services:4.3.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
diff --git a/exif/build.gradle b/exif/build.gradle
index 618016e..6db201c 100644
--- a/exif/build.gradle
+++ b/exif/build.gradle
@@ -1,4 +1,5 @@
apply plugin: 'com.android.library'
+apply plugin: 'kotlin-android'
android {
compileSdkVersion target_sdk_version
@@ -8,7 +9,7 @@ android {
versionCode 1
versionName "1.0"
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
@@ -22,11 +23,17 @@ android {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
- androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
+ androidTestImplementation 'androidx.test.ext:junit:1.1.1'
+ androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0', {
exclude group: 'com.android.support', module: 'support-annotations'
})
testImplementation 'junit:junit:4.12'
implementation 'org.apache.commons:commons-lang3:3.3.2'
implementation 'commons-io:commons-io:2.6'
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+}
+
+repositories {
+ mavenCentral()
}
diff --git a/exif/src/androidTest/java/jp/juggler/exif/ExampleInstrumentedTest.java b/exif/src/androidTest/java/jp/juggler/exif/ExampleInstrumentedTest.java
deleted file mode 100644
index 5b7720c..0000000
--- a/exif/src/androidTest/java/jp/juggler/exif/ExampleInstrumentedTest.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package jp.juggler.exif;
-
-import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static org.junit.Assert.*;
-
-/**
- * Instrumentation test, which will execute on an Android device.
- *
- * @see Testing documentation
- */
-@RunWith( AndroidJUnit4.class )
-public class ExampleInstrumentedTest{
-
- @Test
- public void useAppContext() throws Exception{
- // Context of the app under test.
- Context appContext = InstrumentationRegistry.getTargetContext();
-
- assertEquals( "jp.juggler.exif.test", appContext.getPackageName() );
- }
-}
diff --git a/exif/src/androidTest/java/jp/juggler/exif/ExampleInstrumentedTest.kt b/exif/src/androidTest/java/jp/juggler/exif/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..cb91b3d
--- /dev/null
+++ b/exif/src/androidTest/java/jp/juggler/exif/ExampleInstrumentedTest.kt
@@ -0,0 +1,25 @@
+package jp.juggler.exif
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Instrumentation test, which will execute on an Android device.
+ *
+ * @see [Testing documentation](http://d.android.com/tools/testing)
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+
+ @Test
+ @Throws(Exception::class)
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+
+ assertEquals("jp.juggler.exif.test", appContext.packageName)
+ }
+}
diff --git a/exif/src/main/java/it/sephiroth/android/library/exif2/ExifInterface.java b/exif/src/main/java/it/sephiroth/android/library/exif2/ExifInterface.java
index ee50807..48140ba 100644
--- a/exif/src/main/java/it/sephiroth/android/library/exif2/ExifInterface.java
+++ b/exif/src/main/java/it/sephiroth/android/library/exif2/ExifInterface.java
@@ -16,9 +16,9 @@
package it.sephiroth.android.library.exif2;
+import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
-import android.os.SystemClock;
import android.util.Log;
import android.util.SparseIntArray;
@@ -65,22 +65,22 @@
*
* @see ExifTag
*/
-public class ExifInterface {
+@SuppressWarnings("unused") public class ExifInterface {
private static final String TAG = "ExifInterface";
-
+
public static final int TAG_NULL = - 1;
public static final int IFD_NULL = - 1;
public static final int DEFINITION_NULL = 0;
-
+
/**
* Tag constants for Jeita EXIF 2.2
*/
-
+
// IFD 0
public static final int TAG_IMAGE_WIDTH = defineTag( IfdId.TYPE_IFD_0, (short) 0x0100 );
public static final int TAG_IMAGE_LENGTH = defineTag( IfdId.TYPE_IFD_0, (short) 0x0101 ); // Image height
public static final int TAG_BITS_PER_SAMPLE = defineTag( IfdId.TYPE_IFD_0, (short) 0x0102 );
-
+
/**
* Value is unsigned int.
* (Read only tag) The compression scheme used for the image data. When a primary image is JPEG compressed, this designation is
@@ -93,14 +93,14 @@ public class ExifInterface {
public static final int TAG_COMPRESSION = defineTag( IfdId.TYPE_IFD_0, (short) 0x0103 );
public static final int TAG_PHOTOMETRIC_INTERPRETATION = defineTag( IfdId.TYPE_IFD_0, (short) 0x0106 );
public static final int TAG_IMAGE_DESCRIPTION = defineTag( IfdId.TYPE_IFD_0, (short) 0x010E );
-
+
/**
* Value is ascii string
* The manufacturer of the recording equipment. This is the manufacturer of the DSC, scanner, video digitizer or other equipment
* that generated the image. When the field is left blank, it is treated as unknown.
*/
public static final int TAG_MAKE = defineTag( IfdId.TYPE_IFD_0, (short) 0x010F );
-
+
/**
* Value is ascii string
* The model name or model number of the equipment. This is the model name of number of the DSC, scanner, video digitizer or
@@ -108,7 +108,7 @@ public class ExifInterface {
*/
public static final int TAG_MODEL = defineTag( IfdId.TYPE_IFD_0, (short) 0x0110 );
public static final int TAG_STRIP_OFFSETS = defineTag( IfdId.TYPE_IFD_0, (short) 0x0111 );
-
+
/**
* Value is int
* The orientation of the camera relative to the scene, when the image was captured. The start point of stored data is:
@@ -129,22 +129,22 @@ public class ExifInterface {
public static final int TAG_SAMPLES_PER_PIXEL = defineTag( IfdId.TYPE_IFD_0, (short) 0x0115 );
public static final int TAG_ROWS_PER_STRIP = defineTag( IfdId.TYPE_IFD_0, (short) 0x0116 );
public static final int TAG_STRIP_BYTE_COUNTS = defineTag( IfdId.TYPE_IFD_0, (short) 0x0117 );
-
- public static final int TAG_INTEROP_VERSION = defineTag(IfdId.TYPE_IFD_INTEROPERABILITY, (short)0x0002);
-
+
+ public static final int TAG_INTEROP_VERSION = defineTag( IfdId.TYPE_IFD_INTEROPERABILITY, (short) 0x0002 );
+
/**
* Value is unsigned double.
* Display/Print resolution of image. Large number of digicam uses 1/72inch, but it has no mean because personal computer doesn't
* use this value to display/print out.
*/
public static final int TAG_X_RESOLUTION = defineTag( IfdId.TYPE_IFD_0, (short) 0x011A );
-
+
/**
* @see #TAG_X_RESOLUTION
*/
public static final int TAG_Y_RESOLUTION = defineTag( IfdId.TYPE_IFD_0, (short) 0x011B );
public static final int TAG_PLANAR_CONFIGURATION = defineTag( IfdId.TYPE_IFD_0, (short) 0x011C );
-
+
/**
* Value is unsigned int.
* Unit of XResolution(0x011a)/YResolution(0x011b)
@@ -158,20 +158,20 @@ public class ExifInterface {
*/
public static final int TAG_RESOLUTION_UNIT = defineTag( IfdId.TYPE_IFD_0, (short) 0x0128 );
public static final int TAG_TRANSFER_FUNCTION = defineTag( IfdId.TYPE_IFD_0, (short) 0x012D );
-
+
/**
* Value is ascii string
* Shows firmware(internal software of digicam) version number.
*/
public static final int TAG_SOFTWARE = defineTag( IfdId.TYPE_IFD_0, (short) 0x0131 );
-
+
/**
* Value is ascii string (20)
* Date/Time of image was last modified. Data format is "YYYY:MM:DD HH:MM:SS"+0x00, total 20bytes. In usual, it has the same
* value of DateTimeOriginal(0x9003)
*/
public static final int TAG_DATE_TIME = defineTag( IfdId.TYPE_IFD_0, (short) 0x0132 );
-
+
/**
* Vallue is ascii String
* This tag records the name of the camera owner, photographer or image creator. The detailed format is not specified, but it is
@@ -185,7 +185,7 @@ public class ExifInterface {
public static final int TAG_Y_CB_CR_SUB_SAMPLING = defineTag( IfdId.TYPE_IFD_0, (short) 0x0212 );
public static final int TAG_Y_CB_CR_POSITIONING = defineTag( IfdId.TYPE_IFD_0, (short) 0x0213 );
public static final int TAG_REFERENCE_BLACK_WHITE = defineTag( IfdId.TYPE_IFD_0, (short) 0x0214 );
-
+
/**
* Values is ascii string
* Shows copyright information
@@ -197,13 +197,13 @@ public class ExifInterface {
public static final int TAG_JPEG_INTERCHANGE_FORMAT = defineTag( IfdId.TYPE_IFD_1, (short) 0x0201 );
public static final int TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = defineTag( IfdId.TYPE_IFD_1, (short) 0x0202 );
// IFD Exif Tags
-
+
/**
* Value is unsigned double
* Exposure time (reciprocal of shutter speed). Unit is second
*/
public static final int TAG_EXPOSURE_TIME = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0x829A );
-
+
/**
* Value is unsigned double
* The actual F-number(F-stop) of lens when the image was taken
@@ -211,7 +211,7 @@ public class ExifInterface {
* @see #TAG_APERTURE_VALUE
*/
public static final int TAG_F_NUMBER = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0x829D );
-
+
/**
* Value is unsigned int.
* Exposure program that the camera used when image was taken.
@@ -228,7 +228,7 @@ public class ExifInterface {
*/
public static final int TAG_EXPOSURE_PROGRAM = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0x8822 );
public static final int TAG_SPECTRAL_SENSITIVITY = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0x8824 );
-
+
/**
* Value is unsigned int.
* CCD sensitivity equivalent to Ag-Hr film speedrate.
@@ -236,20 +236,20 @@ public class ExifInterface {
*/
public static final int TAG_ISO_SPEED_RATINGS = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0x8827 );
public static final int TAG_OECF = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0x8828 );
-
+
/**
* ASCII string (4).
* The version of this standard supported. Nonexistence of this field is taken to mean nonconformance to the standard (see
* section 4.2). Conformance to this standard is indicated by recording "0220" as 4-byte ASCII
*/
public static final int TAG_EXIF_VERSION = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0x9000 );
-
+
/**
* Value is ascii string (20)
* Date/Time of original image taken. This value should not be modified by user program.
*/
public static final int TAG_DATE_TIME_ORIGINAL = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0x9003 );
-
+
/**
* Value is ascii string (20)
* Date/Time of image digitized. Usually, it contains the same value of DateTimeOriginal(0x9003).
@@ -257,15 +257,14 @@ public class ExifInterface {
public static final int TAG_DATE_TIME_DIGITIZED = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0x9004 );
public static final int TAG_COMPONENTS_CONFIGURATION = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0x9101 );
public static final int TAG_COMPRESSED_BITS_PER_PIXEL = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0x9102 );
-
+
/**
* Value is signed double.
* Shutter speed. To convert this value to ordinary 'Shutter Speed'; calculate this value's power of 2, then reciprocal. For
* example, if value is '4', shutter speed is 1/(2^4)=1/16 second.
*/
public static final int TAG_SHUTTER_SPEED_VALUE = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0x9201 );
-
-
+
/**
* Value is unsigned double
* The actual aperture value of lens when the image was taken.
@@ -279,19 +278,19 @@ public class ExifInterface {
* @see #TAG_F_NUMBER
*/
public static final int TAG_APERTURE_VALUE = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0x9202 );
-
+
/**
* Value is signed double
* Brightness of taken subject, unit is EV.
*/
public static final int TAG_BRIGHTNESS_VALUE = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0x9203 );
-
+
/**
* Value is signed double.
* The exposure bias. The unit is the APEX value. Ordinarily it is given in the range of -99.99 to 99.99
*/
public static final int TAG_EXPOSURE_BIAS_VALUE = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0x9204 );
-
+
/**
* Value is unsigned double.
* Maximum aperture value of lens.
@@ -302,13 +301,13 @@ public class ExifInterface {
*
*/
public static final int TAG_MAX_APERTURE_VALUE = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0x9205 );
-
+
/**
* Value if signed double.
* Distance to focus point, unit is meter. If value < 0 then focus point is infinite
*/
public static final int TAG_SUBJECT_DISTANCE = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0x9206 );
-
+
/**
* Value is unsigned int.
* Exposure metering method:
@@ -325,7 +324,7 @@ public class ExifInterface {
*
*/
public static final int TAG_METERING_MODE = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0x9207 );
-
+
/**
* Value is unsigned int.
* Light source, actually this means white balance setting.
@@ -355,7 +354,7 @@ public class ExifInterface {
*
*/
public static final int TAG_LIGHT_SOURCE = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0x9208 );
-
+
/**
* Value is unsigned integer
* The 8 bits can be extracted and evaluated in this way:
@@ -398,7 +397,7 @@ public class ExifInterface {
* @see http://www.exif.org/Exif2-2.PDF
*/
public static final int TAG_FLASH = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0x9209 );
-
+
/**
* Value is unsigned double
* Focal length of lens used to take image. Unit is millimeter.
@@ -411,7 +410,7 @@ public class ExifInterface {
public static final int TAG_SUB_SEC_TIME_ORIGINAL = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0x9291 );
public static final int TAG_SUB_SEC_TIME_DIGITIZED = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0x9292 );
public static final int TAG_FLASHPIX_VERSION = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0xA000 );
-
+
/**
* Value is int.
* Normally sRGB (=1) is used to define the color space based on the PC monitor conditions and environment. If a color space
@@ -424,7 +423,7 @@ public class ExifInterface {
*
*/
public static final int TAG_COLOR_SPACE = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0xA001 );
-
+
/**
* Value is unsigned int.
* Specific to compressed data; the valid width of the meaningful image. When a compressed file is recorded, the valid width of
@@ -432,7 +431,7 @@ public class ExifInterface {
* not exist in an uncompressed file.
*/
public static final int TAG_PIXEL_X_DIMENSION = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0xA002 );
-
+
/**
* @see #TAG_PIXEL_X_DIMENSION
*/
@@ -441,7 +440,7 @@ public class ExifInterface {
public static final int TAG_INTEROPERABILITY_IFD = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0xA005 );
public static final int TAG_FLASH_ENERGY = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0xA20B );
public static final int TAG_SPATIAL_FREQUENCY_RESPONSE = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0xA20C );
-
+
/**
* Value is unsigned double.
* Indicates the number of pixels in the image width (X) direction per FocalPlaneResolutionUnit on the camera focal plane. CCD's
@@ -450,12 +449,12 @@ public class ExifInterface {
* @see #TAG_FOCAL_PLANE_RESOLUTION_UNIT
*/
public static final int TAG_FOCAL_PLANE_X_RESOLUTION = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0xA20E );
-
+
/**
* @see #TAG_FOCAL_PLANE_X_RESOLUTION
*/
public static final int TAG_FOCAL_PLANE_Y_RESOLUTION = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0xA20F );
-
+
/**
* Value is unsigned int.
* Unit of FocalPlaneXResoluton/FocalPlaneYResolution.
@@ -476,7 +475,7 @@ public class ExifInterface {
public static final int TAG_FOCAL_PLANE_RESOLUTION_UNIT = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0xA210 );
public static final int TAG_SUBJECT_LOCATION = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0xA214 );
public static final int TAG_EXPOSURE_INDEX = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0xA215 );
-
+
/**
* Value is unsigned int.
* Indicates the image sensor type on the camera or input device. The values are as follows:
@@ -496,7 +495,7 @@ public class ExifInterface {
public static final int TAG_SCENE_TYPE = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0xA301 );
public static final int TAG_CFA_PATTERN = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0xA302 );
public static final int TAG_CUSTOM_RENDERED = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0xA401 );
-
+
/**
* Value is int.
* This tag indicates the exposure mode set when the image was shot. In auto-bracketing mode, the camera shoots a series of
@@ -510,14 +509,14 @@ public class ExifInterface {
*/
public static final int TAG_EXPOSURE_MODE = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0xA402 );
public static final int TAG_WHITE_BALANCE = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0xA403 );
-
+
/**
* Value is double.
* This tag indicates the digital zoom ratio when the image was shot. If the numerator of the recorded value is 0, this indicates
* that digital zoom was not used
*/
public static final int TAG_DIGITAL_ZOOM_RATIO = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0xA404 );
-
+
/**
* Value is unsigned int.
* This tag indicates the equivalent focal length assuming a 35mm film camera, in mm.
@@ -529,7 +528,7 @@ public class ExifInterface {
*
*/
public static final int TAG_FOCAL_LENGTH_IN_35_MM_FILE = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0xA405 );
-
+
/**
* Value is int.
* This tag indicates the type of scene that was shot. It can also be used to record the mode in which the image was shot. Note
@@ -543,7 +542,7 @@ public class ExifInterface {
*
*/
public static final int TAG_SCENE_CAPTURE_TYPE = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0xA406 );
-
+
/**
* Value is int.
* This tag indicates the degree of overall image gain adjustment.
@@ -557,7 +556,7 @@ public class ExifInterface {
*
*/
public static final int TAG_GAIN_CONTROL = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0xA407 );
-
+
/**
* Value is int.
* This tag indicates the direction of contrast processing applied by the camera when the image was shot.
@@ -569,7 +568,7 @@ public class ExifInterface {
*
*/
public static final int TAG_CONTRAST = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0xA408 );
-
+
/**
* Value is int.
* This tag indicates the direction of saturation processing applied by the camera when the image was shot.
@@ -581,7 +580,7 @@ public class ExifInterface {
*
*/
public static final int TAG_SATURATION = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0xA409 );
-
+
/**
* Value is int.
* This tag indicates the direction of sharpness processing applied by the camera when the image was shot
@@ -594,7 +593,7 @@ public class ExifInterface {
*/
public static final int TAG_SHARPNESS = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0xA40A );
public static final int TAG_DEVICE_SETTING_DESCRIPTION = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0xA40B );
-
+
/**
* Value is int.
* This tag indicates the distance to the subject.
@@ -607,12 +606,12 @@ public class ExifInterface {
*
*/
public static final int TAG_SUBJECT_DISTANCE_RANGE = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0xA40C );
-
+
/**
* {@link ExifTag#TYPE_ASCII}
*/
public static final int TAG_IMAGE_UNIQUE_ID = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0xA420 );
-
+
/**
* Lens Specifications. The value it's a 4 rational containing:
*
@@ -621,26 +620,29 @@ public class ExifInterface {
* - Minimum F Number in the minimum focal length
* - Maximum F Number in the maximum focal length
*
- *
+ *
* {@link ExifTag#TYPE_RATIONAL}
- * @since EXIF 2.3
+ *
* @see it.sephiroth.android.library.exif2.ExifUtil#processLensSpecifications(Rational[])
+ * @since EXIF 2.3
*/
public static final int TAG_LENS_SPECS = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0xA432 );
-
+
/**
* Lens maker
* {@link ExifTag#TYPE_ASCII}
+ *
* @since EXIF 2.3
*/
public static final int TAG_LENS_MAKE = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0xA433 );
/**
* Lens model name and number
* {@link ExifTag#TYPE_ASCII}
+ *
* @since EXIF 2.3
*/
public static final int TAG_LENS_MODEL = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0xA434 );
-
+
/**
* The SensitivityType tag indicates which one of the parameters of ISO12232 is the
* PhotographicSensitivity tag. Although it is an optional tag, it should be recorded
@@ -659,25 +661,25 @@ public class ExifInterface {
*
7: Standard output sensitivity (SOS) and recommended exposure index (REI) and ISO speed
* Other: Reserved
*
- *
+ *
* {@link ExifTag#TYPE_UNSIGNED_SHORT}
+ *
* @see it.sephiroth.android.library.exif2.ExifInterface.SensitivityType
* @since EXIF 2.3
*/
public static final int TAG_SENSITIVITY_TYPE = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0x8830 );
-
+
public static final int TAG_STANDARD_OUTPUT_SENSITIVITY = defineTag( IfdId.TYPE_IFD_EXIF, (short) 0x8831 );
-
-
+
// IFD GPS tags
public static final int TAG_GPS_VERSION_ID = defineTag( IfdId.TYPE_IFD_GPS, (short) 0 );
-
+
/**
* Value is string(1)
* Indicates whether the latitude is north or south latitude. The ASCII value 'N' indicates north latitude, and 'S' is south latitude.
*/
public static final int TAG_GPS_LATITUDE_REF = defineTag( IfdId.TYPE_IFD_GPS, (short) 1 );
-
+
/**
* Value is string.
* Indicates the latitude. The latitude is expressed as three RATIONAL values giving the degrees, minutes, and
@@ -686,13 +688,13 @@ public class ExifInterface {
* decimal places, the format would be dd/1,mmmm/100,0/1.
*/
public static final int TAG_GPS_LATITUDE = defineTag( IfdId.TYPE_IFD_GPS, (short) 2 );
-
+
/**
* Value is string(1)
* Indicates whether the longitude is east or west longitude. ASCII 'E' indicates east longitude, and 'W' is west longitude.
*/
public static final int TAG_GPS_LONGITUDE_REF = defineTag( IfdId.TYPE_IFD_GPS, (short) 3 );
-
+
/**
* Value is string.
* Indicates the longitude. The longitude is expressed as three RATIONAL values giving the degrees, minutes, and
@@ -701,7 +703,7 @@ public class ExifInterface {
* decimal places, the format would be ddd/1,mmmm/100,0/1.
*/
public static final int TAG_GPS_LONGITUDE = defineTag( IfdId.TYPE_IFD_GPS, (short) 4 );
-
+
/**
* Value is byte
* Indicates the altitude used as the reference altitude. If the reference is sea level and the altitude is above sea level,
@@ -709,7 +711,7 @@ public class ExifInterface {
* the GPSAltitude tag. The reference unit is meters. Note that this tag is BYTE type, unlike other reference tags
*/
public static final int TAG_GPS_ALTITUDE_REF = defineTag( IfdId.TYPE_IFD_GPS, (short) 5 );
-
+
/**
* Value is string.
* Indicates the altitude based on the reference in GPSAltitudeRef. Altitude is expressed as one RATIONAL value. The reference unit is meters.
@@ -720,13 +722,13 @@ public class ExifInterface {
public static final int TAG_GPS_STATUS = defineTag( IfdId.TYPE_IFD_GPS, (short) 9 );
public static final int TAG_GPS_MEASURE_MODE = defineTag( IfdId.TYPE_IFD_GPS, (short) 10 );
public static final int TAG_GPS_DOP = defineTag( IfdId.TYPE_IFD_GPS, (short) 11 );
-
+
/**
* Value is string(1).
* Indicates the unit used to express the GPS receiver speed of movement. 'K' 'M' and 'N' represents kilometers per hour, miles per hour, and knots.
*/
public static final int TAG_GPS_SPEED_REF = defineTag( IfdId.TYPE_IFD_GPS, (short) 12 );
-
+
/**
* Value is string.
* Indicates the speed of GPS receiver movement
@@ -751,51 +753,48 @@ public class ExifInterface {
public static final int TAG_GPS_DIFFERENTIAL = defineTag( IfdId.TYPE_IFD_GPS, (short) 30 );
// IFD Interoperability tags
public static final int TAG_INTEROPERABILITY_INDEX = defineTag( IfdId.TYPE_IFD_INTEROPERABILITY, (short) 1 );
-
-
-
-
+
public static final ByteOrder DEFAULT_BYTE_ORDER = ByteOrder.BIG_ENDIAN;
private ExifData mData = new ExifData( DEFAULT_BYTE_ORDER );
private static final String NULL_ARGUMENT_STRING = "Argument is null";
-
+
private static final String GPS_DATE_FORMAT_STR = "yyyy:MM:dd";
- private static final DateFormat mGPSDateStampFormat = new SimpleDateFormat( GPS_DATE_FORMAT_STR );
+ @SuppressLint("SimpleDateFormat") private static final DateFormat mGPSDateStampFormat = new SimpleDateFormat( GPS_DATE_FORMAT_STR );
private static final String DATETIME_FORMAT_STR = "yyyy:MM:dd kk:mm:ss";
- private static final DateFormat mDateTimeStampFormat = new SimpleDateFormat( DATETIME_FORMAT_STR );
-
+ @SuppressLint("SimpleDateFormat") private static final DateFormat mDateTimeStampFormat = new SimpleDateFormat( DATETIME_FORMAT_STR );
+
/**
* Tags that contain offset markers. These are included in the banned
* defines.
*/
- private static HashSet sOffsetTags = new HashSet();
-
- static {
+ private static HashSet< Short > sOffsetTags = new HashSet<>();
+
+ static{
sOffsetTags.add( getTrueTagKey( TAG_GPS_IFD ) );
sOffsetTags.add( getTrueTagKey( TAG_EXIF_IFD ) );
sOffsetTags.add( getTrueTagKey( TAG_JPEG_INTERCHANGE_FORMAT ) );
sOffsetTags.add( getTrueTagKey( TAG_INTEROPERABILITY_IFD ) );
sOffsetTags.add( getTrueTagKey( TAG_STRIP_OFFSETS ) );
}
-
+
/**
* Tags with definitions that cannot be overridden (banned defines).
*/
- protected static HashSet sBannedDefines = new HashSet( sOffsetTags );
-
- static {
+ protected static HashSet< Short > sBannedDefines = new HashSet<>( sOffsetTags );
+
+ static{
sBannedDefines.add( getTrueTagKey( TAG_NULL ) );
sBannedDefines.add( getTrueTagKey( TAG_JPEG_INTERCHANGE_FORMAT_LENGTH ) );
sBannedDefines.add( getTrueTagKey( TAG_STRIP_BYTE_COUNTS ) );
}
-
+
private final Calendar mGPSTimeStampCalendar = Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) );
private SparseIntArray mTagInfo = null;
-
- public ExifInterface() {
+
+ public ExifInterface(){
mGPSDateStampFormat.setTimeZone( TimeZone.getTimeZone( "UTC" ) );
}
-
+
/**
* Returns true if tag TID is one of the following: {@link #TAG_EXIF_IFD},
* {@link #TAG_GPS_IFD}, {@link #TAG_JPEG_INTERCHANGE_FORMAT},
@@ -807,56 +806,52 @@ public ExifInterface() {
* {@link #getTrueTagKey}).
* @return true if the TID is that of an offset tag.
*/
- protected static boolean isOffsetTag( short tag ) {
+ protected static boolean isOffsetTag( short tag ){
return sOffsetTags.contains( tag );
}
-
+
/**
* Returns the Orientation ExifTag value for a given number of degrees.
*
* @param degrees the amount an image is rotated in degrees.
*/
- public static short getOrientationValueForRotation( int degrees ) {
+ public static short getOrientationValueForRotation( int degrees ){
degrees %= 360;
- if( degrees < 0 ) {
+ if( degrees < 0 ){
degrees += 360;
}
- if( degrees < 90 ) {
+ if( degrees < 90 ){
return Orientation.TOP_LEFT; // 0 degrees
- }
- else if( degrees < 180 ) {
+ }else if( degrees < 180 ){
return Orientation.RIGHT_TOP; // 90 degrees cw
- }
- else if( degrees < 270 ) {
+ }else if( degrees < 270 ){
return Orientation.BOTTOM_LEFT; // 180 degrees
- }
- else {
+ }else{
return Orientation.RIGHT_BOTTOM; // 270 degrees cw
}
}
-
+
/**
* Returns the rotation degrees corresponding to an ExifTag Orientation
* value.
*
* @param orientation the ExifTag Orientation value.
*/
- @SuppressWarnings( "unused" )
- public static int getRotationForOrientationValue( short orientation ) {
- switch( orientation ) {
- case Orientation.TOP_LEFT:
- return 0;
- case Orientation.RIGHT_TOP:
- return 90;
- case Orientation.BOTTOM_LEFT:
- return 180;
- case Orientation.RIGHT_BOTTOM:
- return 270;
- default:
- return 0;
+ @SuppressWarnings("unused")
+ public static int getRotationForOrientationValue( short orientation ){
+ switch( orientation ){
+ default:
+ case Orientation.TOP_LEFT:
+ return 0;
+ case Orientation.RIGHT_TOP:
+ return 90;
+ case Orientation.BOTTOM_LEFT:
+ return 180;
+ case Orientation.RIGHT_BOTTOM:
+ return 270;
}
}
-
+
/**
* Given the value from {@link #TAG_FOCAL_PLANE_RESOLUTION_UNIT} or {@link #TAG_RESOLUTION_UNIT}
* this method will return the corresponding value in millimeters
@@ -864,27 +859,26 @@ public static int getRotationForOrientationValue( short orientation ) {
* @param resolution {@link #TAG_FOCAL_PLANE_RESOLUTION_UNIT} or {@link #TAG_RESOLUTION_UNIT}
* @return resolution in millimeters
*/
- @SuppressWarnings( "unused" )
- public double getResolutionUnit( int resolution ) {
- switch( resolution ) {
- case 1:
- case ResolutionUnit.INCHES:
- return 25.4;
-
- case ResolutionUnit.CENTIMETERS:
- return 10;
-
- case ResolutionUnit.MILLIMETERS:
- return 1;
-
- case ResolutionUnit.MICROMETERS:
- return .001;
-
- default:
- return 25.4;
- }
- }
-
+ @SuppressWarnings("unused")
+ public double getResolutionUnit( int resolution ){
+ switch( resolution ){
+ default:
+ case 1:
+ case ResolutionUnit.INCHES:
+ return 25.4;
+
+ case ResolutionUnit.CENTIMETERS:
+ return 10;
+
+ case ResolutionUnit.MILLIMETERS:
+ return 1;
+
+ case ResolutionUnit.MICROMETERS:
+ return .001;
+
+ }
+ }
+
/**
* Gets the double representation of the GPS latitude or longitude
* coordinate.
@@ -897,67 +891,67 @@ public double getResolutionUnit( int resolution ) {
* @return the GPS coordinate represented as degrees + minutes/60 +
* seconds/3600
*/
- public static double convertLatOrLongToDouble( Rational[] coordinate, String reference ) {
- try {
- double degrees = coordinate[0].toDouble();
- double minutes = coordinate[1].toDouble();
- double seconds = coordinate[2].toDouble();
+ public static double convertLatOrLongToDouble( Rational[] coordinate, String reference ){
+ try{
+ double degrees = coordinate[ 0 ].toDouble();
+ double minutes = coordinate[ 1 ].toDouble();
+ double seconds = coordinate[ 2 ].toDouble();
double result = degrees + minutes / 60.0 + seconds / 3600.0;
- if( ( reference.startsWith( "S" ) || reference.startsWith( "W" ) ) ) {
+ if( ( reference.startsWith( "S" ) || reference.startsWith( "W" ) ) ){
return - result;
}
return result;
- } catch( ArrayIndexOutOfBoundsException e ) {
+ }catch( ArrayIndexOutOfBoundsException e ){
throw new IllegalArgumentException();
}
}
-
- protected static int[] getAllowedIfdsFromInfo( int info ) {
+
+ protected static int[] getAllowedIfdsFromInfo( int info ){
int ifdFlags = getAllowedIfdFlagsFromInfo( info );
int[] ifds = IfdData.getIfds();
- ArrayList l = new ArrayList();
- for( int i = 0; i < IfdId.TYPE_IFD_COUNT; i++ ) {
+ ArrayList< Integer > l = new ArrayList<>();
+ for( int i = 0 ; i < IfdId.TYPE_IFD_COUNT ; i++ ){
int flag = ( ifdFlags >> i ) & 1;
- if( flag == 1 ) {
- l.add( ifds[i] );
+ if( flag == 1 ){
+ l.add( ifds[ i ] );
}
}
- if( l.size() <= 0 ) {
+ if( l.size() <= 0 ){
return null;
}
- int[] ret = new int[l.size()];
+ int[] ret = new int[ l.size() ];
int j = 0;
- for( int i : l ) {
- ret[j++] = i;
+ for( int i : l ){
+ ret[ j++ ] = i;
}
return ret;
}
-
+
/**
* Reads the exif tags from a file, clearing this ExifInterface object's
* existing exif tags.
*
* @param inFileName a string representing the filepath to jpeg file.
- * @param options bit flag which defines which type of tags to process, see {@link it.sephiroth.android.library.exif2.ExifInterface.Options}
- * @see #readExif(java.io.InputStream, int)
+ * @param options bit flag which defines which type of tags to process, see {@link it.sephiroth.android.library.exif2.ExifInterface.Options}
* @throws java.io.IOException
+ * @see #readExif(java.io.InputStream, int)
*/
- @SuppressWarnings( "unused" )
- public void readExif( String inFileName, int options ) throws IOException {
- if( inFileName == null ) {
+ @SuppressWarnings("unused")
+ public void readExif( String inFileName, int options ) throws IOException{
+ if( inFileName == null ){
throw new IllegalArgumentException( NULL_ARGUMENT_STRING );
}
InputStream is = null;
- try {
+ try{
is = new BufferedInputStream( new FileInputStream( inFileName ) );
readExif( is, options );
- } catch( IOException e ) {
+ }catch( IOException e ){
closeSilently( is );
throw e;
}
is.close();
}
-
+
/**
* Reads the exif tags from an InputStream, clearing this ExifInterface
* object's existing exif tags.
@@ -970,51 +964,51 @@ public void readExif( String inFileName, int options ) throws IOException {
*
*
* @param inStream an InputStream containing a jpeg compressed image.
- * @param options bit flag which defines which type of tags to process, see {@link it.sephiroth.android.library.exif2.ExifInterface.Options}
+ * @param options bit flag which defines which type of tags to process, see {@link it.sephiroth.android.library.exif2.ExifInterface.Options}
* @throws java.io.IOException
*/
- @SuppressWarnings( "unused" )
- public void readExif( InputStream inStream, int options ) throws IOException {
- if( inStream == null ) {
+ @SuppressWarnings("unused")
+ public void readExif( InputStream inStream, int options ) throws IOException{
+ if( inStream == null ){
throw new IllegalArgumentException( NULL_ARGUMENT_STRING );
}
ExifData d;
- try {
+ try{
d = new ExifReader( this ).read( inStream, options );
- } catch( ExifInvalidFormatException e ) {
+ }catch( ExifInvalidFormatException e ){
throw new IOException( "Invalid exif format : " + e );
}
mData = d;
}
-
- protected static void closeSilently( Closeable c ) {
- if( c != null ) {
- try {
+
+ protected static void closeSilently( Closeable c ){
+ if( c != null ){
+ try{
c.close();
- } catch( Throwable e ) {
+ }catch( Throwable e ){
// ignored
}
}
}
-
+
/**
* Sets the exif tags, clearing this ExifInterface object's existing exif
* tags.
*
* @param tags a collection of exif tags to set.
*/
- public void setExif( Collection tags ) {
+ public void setExif( Collection< ExifTag > tags ){
clearExif();
setTags( tags );
}
-
+
/**
* Clears this ExifInterface object's existing exif tags.
*/
- public void clearExif() {
+ public void clearExif(){
mData = new ExifData( DEFAULT_BYTE_ORDER );
}
-
+
/**
* Puts a collection of ExifTags into this ExifInterface objects's tags. Any
* previous ExifTags with the same TID and IFDs will be removed.
@@ -1022,13 +1016,13 @@ public void clearExif() {
* @param tags a Collection of ExifTags.
* @see #setTag
*/
- public void setTags( Collection tags ) {
+ public void setTags( Collection< ExifTag > tags ){
if( null == tags ) return;
- for( ExifTag t : tags ) {
+ for( ExifTag t : tags ){
setTag( t );
}
}
-
+
/**
* Puts an ExifTag into this ExifInterface object's tags, removing a
* previous ExifTag with the same TID and IFD. The IFD it is put into will
@@ -1038,172 +1032,173 @@ public void setTags( Collection tags ) {
* @return the previous ExifTag with the same TID and IFD or null if none
* exists.
*/
- public ExifTag setTag( ExifTag tag ) {
+ public ExifTag setTag( ExifTag tag ){
return mData.addTag( tag );
}
-
- @SuppressWarnings( "unused" )
- public void writeExif( final String dstFilename ) throws IOException {
+
+ @SuppressWarnings("unused")
+ public void writeExif( final String dstFilename ) throws IOException{
Log.i( TAG, "writeExif: " + dstFilename );
-
+
// create a backup file
File dst_file = new File( dstFilename );
File bak_file = new File( dstFilename + ".t" );
-
+
// try to delete old copy of backup
// Log.d( TAG, "delete old backup file" );
+ //noinspection ResultOfMethodCallIgnored
bak_file.delete();
-
+
// rename dst file into backup file
// Log.d( TAG, "rename dst into bak" )
// if( ! dst_file.renameTo( bak_file ) ) return;
-
- try {
+
+ try{
// Log.d( TAG, "try to write into dst" );
// writeExif( bak_file.getAbsolutePath(), dst_file.getAbsolutePath() );
-
+
// Trying to write into bak_file using dst_file as source
writeExif( dst_file.getAbsolutePath(), bak_file.getAbsolutePath() );
-
+
// Now switch bak into dst
// Log.d( TAG, "rename the bak into dst" );
+ //noinspection ResultOfMethodCallIgnored
bak_file.renameTo( dst_file );
- } catch( IOException e ) {
- throw e;
- } finally {
+ }finally{
// deleting backup file
+ //noinspection ResultOfMethodCallIgnored
bak_file.delete();
}
}
-
- @SuppressWarnings( "unused" )
- public void writeExif( final String srcFilename, final String dstFilename ) throws IOException {
+
+ @SuppressWarnings("unused")
+ public void writeExif( final String srcFilename, final String dstFilename ) throws IOException{
Log.i( TAG, "writeExif: " + dstFilename );
-
+
// src and dst cannot be the same
if( srcFilename.equals( dstFilename ) ) return;
-
+
// srcFilename is used *ONLY* to read the image uncompressed data
// exif tags are not used here
-
+
// 3. rename dst file into backup file
FileInputStream input = new FileInputStream( srcFilename );
FileOutputStream output = new FileOutputStream( dstFilename );
-
+
int position = writeExif_internal( input, output, mData );
-
+
// 7. write the rest of the image..
FileChannel in_channel = input.getChannel();
FileChannel out_channel = output.getChannel();
in_channel.transferTo( position, in_channel.size() - position, out_channel );
output.flush();
-
+
+ //noinspection deprecation
IOUtils.closeQuietly( input );
+ //noinspection deprecation
IOUtils.closeQuietly( output );
}
-
-
- public void writeExif( final InputStream input, final String dstFilename ) throws IOException {
+
+ public void writeExif( final InputStream input, final String dstFilename ) throws IOException{
Log.i( TAG, "writeExif: " + dstFilename );
-
+
// inpur is used *ONLY* to read the image uncompressed data
// exif tags are not used here
-
+
FileOutputStream output = new FileOutputStream( dstFilename );
writeExif_internal( input, output, mData );
-
+
// 7. write the rest of the image..
IOUtils.copy( input, output );
-
+
output.flush();
output.close();
}
-
- @SuppressWarnings( "unused" )
- public void writeExif( final Bitmap input, final String dstFilename, int quality ) throws IOException {
+
+ @SuppressWarnings("unused")
+ public void writeExif( final Bitmap input, final String dstFilename, int quality ) throws IOException{
Log.i( TAG, "writeExif: " + dstFilename );
-
+
// inpur is used *ONLY* to read the image uncompressed data
// exif tags are not used here
-
+
ByteArrayOutputStream out = new ByteArrayOutputStream();
input.compress( Bitmap.CompressFormat.JPEG, quality, out );
-
+
ByteArrayInputStream in = new ByteArrayInputStream( out.toByteArray() );
out.close();
-
+
writeExif( in, dstFilename );
}
-
- private static int writeExif_internal( final InputStream input, final OutputStream output, ExifData exifData ) throws IOException {
+
+ private static int writeExif_internal( final InputStream input, final OutputStream output, ExifData exifData ) throws IOException{
// Log.i( TAG, "writeExif_internal" );
-
+
// 1. read the output file first
ExifInterface src_exif = new ExifInterface();
src_exif.readExif( input, 0 );
-
+
// 4. Create the destination outputstream
// 5. write headers
output.write( 0xFF );
output.write( JpegHeader.TAG_SOI );
-
- final List sections = src_exif.mData.getSections();
-
+
+ final List< ExifParser.Section > sections = src_exif.mData.getSections();
+
// 6. write all the sections from the srcFilename
- if( sections.get( 0 ).type != JpegHeader.TAG_M_JFIF ) {
+ if( sections.get( 0 ).type != JpegHeader.TAG_M_JFIF ){
Log.w( TAG, "first section is not a JFIF or EXIF tag" );
output.write( JpegHeader.JFIF_HEADER );
}
-
+
// 6.1 write the *new* EXIF tag
ExifOutputStream eo = new ExifOutputStream( src_exif );
eo.setExifData( exifData );
eo.writeExifData( output );
-
+
// 6.2 write all the sections except for the SOS ( start of scan )
- for( int a = 0; a < sections.size() - 1; a++ ) {
+ for( int a = 0 ; a < sections.size() - 1 ; a++ ){
ExifParser.Section current = sections.get( a );
// Log.v( TAG, "writing section.. " + String.format( "0x%2X", current.type ) );
output.write( 0xFF );
output.write( current.type );
output.write( current.data );
}
-
+
// 6.3 write the last SOS marker
ExifParser.Section current = sections.get( sections.size() - 1 );
// Log.v( TAG, "writing last section.. " + String.format( "0x%2X", current.type ) );
output.write( 0xFF );
output.write( current.type );
output.write( current.data );
-
+
// return the position where the input stream should be copied
return src_exif.mData.mUncompressedDataPosition;
}
-
-
+
/**
* Get the exif tags in this ExifInterface object or null if none exist.
*
* @return a List of {@link ExifTag}s.
*/
- public List getAllTags() {
+ public List< ExifTag > getAllTags(){
return mData.getAllTags();
}
-
+
/**
* Reads the exif tags from a byte array, clearing this ExifInterface
* object's existing exif tags.
*
- * @param jpeg a byte array containing a jpeg compressed image.
+ * @param jpeg a byte array containing a jpeg compressed image.
* @param options bit flag which defines which type of tags to process, see {@link it.sephiroth.android.library.exif2.ExifInterface.Options}
* @throws java.io.IOException
* @see #readExif(java.io.InputStream, int)
*/
- @SuppressWarnings( "unused" )
- public void readExif( byte[] jpeg, int options ) throws IOException {
+ @SuppressWarnings("unused")
+ public void readExif( byte[] jpeg, int options ) throws IOException{
readExif( new ByteArrayInputStream( jpeg ), options );
}
-
+
/**
* Returns a list of ExifTags that share a TID (which can be obtained by
* calling {@link #getTrueTagKey} on a defined tag constant) or null if none
@@ -1213,11 +1208,11 @@ public void readExif( byte[] jpeg, int options ) throws IOException {
* {@link #defineTag}).
* @return a List of {@link ExifTag}s.
*/
- @SuppressWarnings( "unused" )
- public List getTagsForTagId( short tagId ) {
+ @SuppressWarnings("unused")
+ public List< ExifTag > getTagsForTagId( short tagId ){
return mData.getAllTagsForTagId( tagId );
}
-
+
/**
* Returns a list of ExifTags that share an IFD (which can be obtained by
* calling {@link #getTrueIfd(int)} on a defined tag constant) or null if none
@@ -1227,11 +1222,11 @@ public List getTagsForTagId( short tagId ) {
* {@link #defineTag}).
* @return a List of {@link ExifTag}s.
*/
- @SuppressWarnings( "unused" )
- public List getTagsForIfdId( int ifdId ) {
+ @SuppressWarnings("unused")
+ public List< ExifTag > getTagsForIfdId( int ifdId ){
return mData.getAllTagsForIfd( ifdId );
}
-
+
/**
* Returns the ExifTag in that tag's default IFD for a defined tag constant
* or null if none exists.
@@ -1239,11 +1234,11 @@ public List getTagsForIfdId( int ifdId ) {
* @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
* @return an {@link ExifTag} or null if none exists.
*/
- public ExifTag getTag( int tagId ) {
+ public ExifTag getTag( int tagId ){
int ifdId = getDefinedTagDefaultIfd( tagId );
return getTag( tagId, ifdId );
}
-
+
/**
* Gets the default IFD for a tag.
*
@@ -1251,51 +1246,51 @@ public ExifTag getTag( int tagId ) {
* @return the default IFD for a tag definition or {@link #IFD_NULL} if no
* definition exists.
*/
- public int getDefinedTagDefaultIfd( int tagId ) {
+ public int getDefinedTagDefaultIfd( int tagId ){
int info = getTagInfo().get( tagId );
- if( info == DEFINITION_NULL ) {
+ if( info == DEFINITION_NULL ){
return IFD_NULL;
}
return getTrueIfd( tagId );
}
-
+
/**
* Gets an ExifTag for an IFD other than the tag's default.
*
* @see #getTag
*/
- public ExifTag getTag( int tagId, int ifdId ) {
- if( ! ExifTag.isValidIfd( ifdId ) ) {
+ public ExifTag getTag( int tagId, int ifdId ){
+ if( ! ExifTag.isValidIfd( ifdId ) ){
return null;
}
return mData.getTag( getTrueTagKey( tagId ), ifdId );
}
-
- protected SparseIntArray getTagInfo() {
- if( mTagInfo == null ) {
+
+ protected SparseIntArray getTagInfo(){
+ if( mTagInfo == null ){
mTagInfo = new SparseIntArray();
initTagInfo();
}
return mTagInfo;
}
-
+
/**
* Returns the default IFD for a tag constant.
*/
- public static int getTrueIfd( int tag ) {
+ public static int getTrueIfd( int tag ){
return tag >>> 16;
}
-
+
/**
* Returns the TID for a tag constant.
*/
- public static short getTrueTagKey( int tag ) {
+ public static short getTrueTagKey( int tag ){
// Truncate
return (short) tag;
}
-
- private void initTagInfo() {
- /**
+
+ private void initTagInfo(){
+ /*
* We put tag information in a 4-bytes integer. The first byte a bitmask
* representing the allowed IFDs of the tag, the second byte is the data
* type, and the last two byte are a short value indicating the default
@@ -1442,16 +1437,16 @@ private void initTagInfo() {
mTagInfo.put( TAG_INTEROPERABILITY_INDEX, interopFlags | ExifTag.TYPE_ASCII << 16 );
mTagInfo.put( TAG_INTEROP_VERSION, interopFlags | ExifTag.TYPE_UNDEFINED << 16 | 4 );
}
-
- protected static int getFlagsFromAllowedIfds( int[] allowedIfds ) {
- if( allowedIfds == null || allowedIfds.length == 0 ) {
+
+ protected static int getFlagsFromAllowedIfds( int[] allowedIfds ){
+ if( allowedIfds == null || allowedIfds.length == 0 ){
return 0;
}
int flags = 0;
int[] ifds = IfdData.getIfds();
- for( int i = 0; i < IfdId.TYPE_IFD_COUNT; i++ ) {
- for( int j : allowedIfds ) {
- if( ifds[i] == j ) {
+ for( int i = 0 ; i < IfdId.TYPE_IFD_COUNT ; i++ ){
+ for( int j : allowedIfds ){
+ if( ifds[ i ] == j ){
flags |= 1 << i;
break;
}
@@ -1459,7 +1454,7 @@ protected static int getFlagsFromAllowedIfds( int[] allowedIfds ) {
}
return flags;
}
-
+
/**
* Returns the value of the ExifTag in that tag's default IFD for a defined
* tag constant or null if none exists or the value could not be cast into
@@ -1468,219 +1463,219 @@ protected static int getFlagsFromAllowedIfds( int[] allowedIfds ) {
* @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
* @return the value of the ExifTag or null if none exists.
*/
- @SuppressWarnings( "unused" )
- public Object getTagValue( int tagId ) {
+ @SuppressWarnings("unused")
+ public Object getTagValue( int tagId ){
int ifdId = getDefinedTagDefaultIfd( tagId );
return getTagValue( tagId, ifdId );
}
-
+
/**
* Gets a tag value for an IFD other than the tag's default.
*
* @see #getTagValue
*/
- public Object getTagValue( int tagId, int ifdId ) {
+ public Object getTagValue( int tagId, int ifdId ){
ExifTag t = getTag( tagId, ifdId );
return ( t == null ) ? null : t.getValue();
}
-
+
/**
* @see #getTagValue
*/
- public String getTagStringValue( int tagId, int ifdId ) {
+ public String getTagStringValue( int tagId, int ifdId ){
ExifTag t = getTag( tagId, ifdId );
- if( t == null ) {
+ if( t == null ){
return null;
}
return t.getValueAsString();
}
-
+
/**
* @see #getTagValue
*/
- public String getTagStringValue( int tagId ) {
+ public String getTagStringValue( int tagId ){
int ifdId = getDefinedTagDefaultIfd( tagId );
return getTagStringValue( tagId, ifdId );
}
-
+
/**
* @see #getTagValue
*/
- @SuppressWarnings( "unused" )
- public Long getTagLongValue( int tagId ) {
+ @SuppressWarnings("unused")
+ public Long getTagLongValue( int tagId ){
int ifdId = getDefinedTagDefaultIfd( tagId );
return getTagLongValue( tagId, ifdId );
}
-
+
/**
* @see #getTagValue
*/
- public Long getTagLongValue( int tagId, int ifdId ) {
+ public Long getTagLongValue( int tagId, int ifdId ){
long[] l = getTagLongValues( tagId, ifdId );
- if( l == null || l.length <= 0 ) {
+ if( l == null || l.length <= 0 ){
return null;
}
- return new Long( l[0] );
+ return l[ 0 ];
}
-
+
/**
* @see #getTagValue
*/
- public long[] getTagLongValues( int tagId, int ifdId ) {
+ public long[] getTagLongValues( int tagId, int ifdId ){
ExifTag t = getTag( tagId, ifdId );
- if( t == null ) {
+ if( t == null ){
return null;
}
return t.getValueAsLongs();
}
-
+
/**
* @see #getTagValue
*/
- public Integer getTagIntValue( int tagId ) {
+ public Integer getTagIntValue( int tagId ){
int ifdId = getDefinedTagDefaultIfd( tagId );
return getTagIntValue( tagId, ifdId );
}
-
+
/**
* @see #getTagValue
*/
- public Integer getTagIntValue( int tagId, int ifdId ) {
+ public Integer getTagIntValue( int tagId, int ifdId ){
int[] l = getTagIntValues( tagId, ifdId );
- if( l == null || l.length <= 0 ) {
+ if( l == null || l.length <= 0 ){
return null;
}
- return new Integer( l[0] );
+ return l[ 0 ];
}
-
+
/**
* @see #getTagValue
*/
- public int[] getTagIntValues( int tagId, int ifdId ) {
+ public int[] getTagIntValues( int tagId, int ifdId ){
ExifTag t = getTag( tagId, ifdId );
- if( t == null ) {
+ if( t == null ){
return null;
}
return t.getValueAsInts();
}
-
+
/**
* @see #getTagValue
*/
- public Byte getTagByteValue( int tagId ) {
+ public Byte getTagByteValue( int tagId ){
int ifdId = getDefinedTagDefaultIfd( tagId );
return getTagByteValue( tagId, ifdId );
}
-
+
/**
* @see #getTagValue
*/
- public Byte getTagByteValue( int tagId, int ifdId ) {
+ public Byte getTagByteValue( int tagId, int ifdId ){
byte[] l = getTagByteValues( tagId, ifdId );
- if( l == null || l.length <= 0 ) {
+ if( l == null || l.length <= 0 ){
return null;
}
- return new Byte( l[0] );
+ return l[ 0 ];
}
-
+
/**
* @see #getTagValue
*/
- public byte[] getTagByteValues( int tagId, int ifdId ) {
+ public byte[] getTagByteValues( int tagId, int ifdId ){
ExifTag t = getTag( tagId, ifdId );
- if( t == null ) {
+ if( t == null ){
return null;
}
return t.getValueAsBytes();
}
-
+
/**
* @see #getTagValue
*/
- public Rational getTagRationalValue( int tagId ) {
+ public Rational getTagRationalValue( int tagId ){
int ifdId = getDefinedTagDefaultIfd( tagId );
return getTagRationalValue( tagId, ifdId );
}
-
+
/**
* @see #getTagValue
*/
- public Rational getTagRationalValue( int tagId, int ifdId ) {
+ public Rational getTagRationalValue( int tagId, int ifdId ){
Rational[] l = getTagRationalValues( tagId, ifdId );
- if( l == null || l.length == 0 ) {
+ if( l == null || l.length == 0 ){
return null;
}
- return new Rational( l[0] );
+ return new Rational( l[ 0 ] );
}
-
- /*
- * Getter methods that are similar to getTagValue. Null is returned if the
- * tag value cannot be cast into the return type.
- */
-
+
+ /*
+ * Getter methods that are similar to getTagValue. Null is returned if the
+ * tag value cannot be cast into the return type.
+ */
+
/**
* @see #getTagValue
*/
- public Rational[] getTagRationalValues( int tagId, int ifdId ) {
+ public Rational[] getTagRationalValues( int tagId, int ifdId ){
ExifTag t = getTag( tagId, ifdId );
- if( t == null ) {
+ if( t == null ){
return null;
}
return t.getValueAsRationals();
}
-
+
/**
* @see #getTagValue
*/
- @SuppressWarnings( "unused" )
- public long[] getTagLongValues( int tagId ) {
+ @SuppressWarnings("unused")
+ public long[] getTagLongValues( int tagId ){
int ifdId = getDefinedTagDefaultIfd( tagId );
return getTagLongValues( tagId, ifdId );
}
-
+
/**
* @see #getTagValue
*/
- @SuppressWarnings( "unused" )
- public int[] getTagIntValues( int tagId ) {
+ @SuppressWarnings("unused")
+ public int[] getTagIntValues( int tagId ){
int ifdId = getDefinedTagDefaultIfd( tagId );
return getTagIntValues( tagId, ifdId );
}
-
+
/**
* @see #getTagValue
*/
- @SuppressWarnings( "unused" )
- public byte[] getTagByteValues( int tagId ) {
+ @SuppressWarnings("unused")
+ public byte[] getTagByteValues( int tagId ){
int ifdId = getDefinedTagDefaultIfd( tagId );
return getTagByteValues( tagId, ifdId );
}
-
+
/**
* @see #getTagValue
*/
- public Rational[] getTagRationalValues( int tagId ) {
+ public Rational[] getTagRationalValues( int tagId ){
int ifdId = getDefinedTagDefaultIfd( tagId );
return getTagRationalValues( tagId, ifdId );
}
-
+
/**
* Checks whether a tag has a defined number of elements.
*
* @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
* @return true if the tag has a defined number of elements.
*/
- @SuppressWarnings( "unused" )
- public boolean isTagCountDefined( int tagId ) {
+ @SuppressWarnings("unused")
+ public boolean isTagCountDefined( int tagId ){
int info = getTagInfo().get( tagId );
// No value in info can be zero, as all tags have a non-zero type
return info != 0 && getComponentCountFromInfo( info ) != ExifTag.SIZE_UNDEFINED;
}
-
- protected static int getComponentCountFromInfo( int info ) {
+
+ protected static int getComponentCountFromInfo( int info ){
return info & 0x0ffff;
}
-
+
/**
* Gets the defined number of elements for a tag.
*
@@ -1688,15 +1683,15 @@ protected static int getComponentCountFromInfo( int info ) {
* @return the number of elements or {@link ExifTag#SIZE_UNDEFINED} if the
* tag or the number of elements is not defined.
*/
- @SuppressWarnings( "unused" )
- public int getDefinedTagCount( int tagId ) {
+ @SuppressWarnings("unused")
+ public int getDefinedTagCount( int tagId ){
int info = getTagInfo().get( tagId );
- if( info == 0 ) {
+ if( info == 0 ){
return ExifTag.SIZE_UNDEFINED;
}
return getComponentCountFromInfo( info );
}
-
+
/**
* Gets the number of elements for an ExifTag in a given IFD.
*
@@ -1706,15 +1701,15 @@ public int getDefinedTagCount( int tagId ) {
* undefined this will return the actual number of elements that is
* in the ExifTag's value.
*/
- @SuppressWarnings( "unused" )
- public int getActualTagCount( int tagId, int ifdId ) {
+ @SuppressWarnings("unused")
+ public int getActualTagCount( int tagId, int ifdId ){
ExifTag t = getTag( tagId, ifdId );
- if( t == null ) {
+ if( t == null ){
return 0;
}
return t.getComponentCount();
}
-
+
/**
* Gets the defined type for a tag.
*
@@ -1722,22 +1717,22 @@ public int getActualTagCount( int tagId, int ifdId ) {
* @return the type.
* @see ExifTag#getDataType()
*/
- @SuppressWarnings( "unused" )
- public short getDefinedTagType( int tagId ) {
+ @SuppressWarnings("unused")
+ public short getDefinedTagType( int tagId ){
int info = getTagInfo().get( tagId );
- if( info == 0 ) {
+ if( info == 0 ){
return - 1;
}
return getTypeFromInfo( info );
}
-
- protected static short getTypeFromInfo( int info ) {
+
+ protected static short getTypeFromInfo( int info ){
return (short) ( ( info >> 16 ) & 0x0ff );
}
-
- protected ExifTag buildUninitializedTag( int tagId ) {
+
+ protected ExifTag buildUninitializedTag( int tagId ){
int info = getTagInfo().get( tagId );
- if( info == 0 ) {
+ if( info == 0 ){
return null;
}
short type = getTypeFromInfo( info );
@@ -1746,7 +1741,7 @@ protected ExifTag buildUninitializedTag( int tagId ) {
int ifdId = getTrueIfd( tagId );
return new ExifTag( getTrueTagKey( tagId ), type, definedCount, ifdId, hasDefinedCount );
}
-
+
/**
* Sets the value of an ExifTag if it exists it's default IFD. The value
* must be the correct type and length for that ExifTag.
@@ -1756,12 +1751,12 @@ protected ExifTag buildUninitializedTag( int tagId ) {
* @return true if success, false if the ExifTag doesn't exist or the value
* is the wrong type/length.
*/
- @SuppressWarnings( "unused" )
- public boolean setTagValue( int tagId, Object val ) {
+ @SuppressWarnings("unused")
+ public boolean setTagValue( int tagId, Object val ){
int ifdId = getDefinedTagDefaultIfd( tagId );
return setTagValue( tagId, ifdId, val );
}
-
+
/**
* Sets the value of an ExifTag if it exists in the given IFD. The value
* must be the correct type and length for that ExifTag.
@@ -1773,31 +1768,31 @@ public boolean setTagValue( int tagId, Object val ) {
* is the wrong type/length.
* @see #setTagValue
*/
- public boolean setTagValue( int tagId, int ifdId, Object val ) {
+ public boolean setTagValue( int tagId, int ifdId, Object val ){
ExifTag t = getTag( tagId, ifdId );
return t != null && t.setValue( val );
}
-
+
/**
* Removes the ExifTag for a tag constant from that tag's default IFD.
*
* @param tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
*/
- public void deleteTag( int tagId ) {
+ public void deleteTag( int tagId ){
int ifdId = getDefinedTagDefaultIfd( tagId );
deleteTag( tagId, ifdId );
}
-
+
/**
* Removes the ExifTag for a tag constant from the given IFD.
*
* @param tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
* @param ifdId the IFD of the ExifTag to remove.
*/
- public void deleteTag( int tagId, int ifdId ) {
+ public void deleteTag( int tagId, int ifdId ){
mData.removeTag( getTrueTagKey( tagId ), ifdId );
}
-
+
/**
* Creates a new tag definition in this ExifInterface object for a given TID
* and default IFD. Creating a definition with the same TID and default IFD
@@ -1812,40 +1807,40 @@ public void deleteTag( int tagId, int ifdId ) {
* @return the defined tag constant (e.g. {@link #TAG_IMAGE_WIDTH}) or
* {@link #TAG_NULL} if the definition could not be made.
*/
- @SuppressWarnings( "unused" )
+ @SuppressWarnings("unused")
public int setTagDefinition(
- short tagId, int defaultIfd, short tagType, short defaultComponentCount, int[] allowedIfds ) {
- if( sBannedDefines.contains( tagId ) ) {
+ short tagId, int defaultIfd, short tagType, short defaultComponentCount, int[] allowedIfds ){
+ if( sBannedDefines.contains( tagId ) ){
return TAG_NULL;
}
- if( ExifTag.isValidType( tagType ) && ExifTag.isValidIfd( defaultIfd ) ) {
+ if( ExifTag.isValidType( tagType ) && ExifTag.isValidIfd( defaultIfd ) ){
int tagDef = defineTag( defaultIfd, tagId );
- if( tagDef == TAG_NULL ) {
+ if( tagDef == TAG_NULL ){
return TAG_NULL;
}
int[] otherDefs = getTagDefinitionsForTagId( tagId );
SparseIntArray infos = getTagInfo();
// Make sure defaultIfd is in allowedIfds
boolean defaultCheck = false;
- for( int i : allowedIfds ) {
- if( defaultIfd == i ) {
+ for( int i : allowedIfds ){
+ if( defaultIfd == i ){
defaultCheck = true;
}
- if( ! ExifTag.isValidIfd( i ) ) {
+ if( ! ExifTag.isValidIfd( i ) ){
return TAG_NULL;
}
}
- if( ! defaultCheck ) {
+ if( ! defaultCheck ){
return TAG_NULL;
}
-
+
int ifdFlags = getFlagsFromAllowedIfds( allowedIfds );
// Make sure no identical tags can exist in allowedIfds
- if( otherDefs != null ) {
- for( int def : otherDefs ) {
+ if( otherDefs != null ){
+ for( int def : otherDefs ){
int tagInfo = infos.get( def );
int allowedFlags = getAllowedIfdFlagsFromInfo( tagInfo );
- if( ( ifdFlags & allowedFlags ) != 0 ) {
+ if( ( ifdFlags & allowedFlags ) != 0 ){
return TAG_NULL;
}
}
@@ -1855,106 +1850,107 @@ public int setTagDefinition(
}
return TAG_NULL;
}
-
- @SuppressWarnings( "unused" )
- protected int getTagDefinition( short tagId, int defaultIfd ) {
+
+ @SuppressWarnings("unused")
+ protected int getTagDefinition( short tagId, int defaultIfd ){
return getTagInfo().get( defineTag( defaultIfd, tagId ) );
}
-
+
/**
* Returns the constant representing a tag with a given TID and default IFD.
*/
- public static int defineTag( int ifdId, short tagId ) {
+ public static int defineTag( int ifdId, short tagId ){
return ( tagId & 0x0000ffff ) | ( ifdId << 16 );
}
-
- protected int[] getTagDefinitionsForTagId( short tagId ) {
+
+ protected int[] getTagDefinitionsForTagId( short tagId ){
int[] ifds = IfdData.getIfds();
- int[] defs = new int[ifds.length];
+ int[] defs = new int[ ifds.length ];
int counter = 0;
SparseIntArray infos = getTagInfo();
- for( int i : ifds ) {
+ for( int i : ifds ){
int def = defineTag( i, tagId );
- if( infos.get( def ) != DEFINITION_NULL ) {
- defs[counter++] = def;
+ if( infos.get( def ) != DEFINITION_NULL ){
+ defs[ counter++ ] = def;
}
}
- if( counter == 0 ) {
+ if( counter == 0 ){
return null;
}
-
+
return Arrays.copyOfRange( defs, 0, counter );
}
-
- @SuppressWarnings( "unused" )
- protected int getTagDefinitionForTag( ExifTag tag ) {
+
+ @SuppressWarnings("unused")
+ protected int getTagDefinitionForTag( ExifTag tag ){
short type = tag.getDataType();
int count = tag.getComponentCount();
int ifd = tag.getIfd();
return getTagDefinitionForTag( tag.getTagId(), type, count, ifd );
}
-
- protected int getTagDefinitionForTag( short tagId, short type, int count, int ifd ) {
+
+ protected int getTagDefinitionForTag( short tagId, short type, int count, int ifd ){
int[] defs = getTagDefinitionsForTagId( tagId );
- if( defs == null ) {
+ if( defs == null ){
return TAG_NULL;
}
SparseIntArray infos = getTagInfo();
int ret = TAG_NULL;
- for( int i : defs ) {
+ for( int i : defs ){
int info = infos.get( i );
short def_type = getTypeFromInfo( info );
int def_count = getComponentCountFromInfo( info );
int[] def_ifds = getAllowedIfdsFromInfo( info );
boolean valid_ifd = false;
- for( int j : def_ifds ) {
- if( j == ifd ) {
+ if( def_ifds != null) for( int j : def_ifds ){
+ if( j == ifd ){
valid_ifd = true;
break;
}
}
- if( valid_ifd && type == def_type && ( count == def_count || def_count == ExifTag.SIZE_UNDEFINED ) ) {
+ if( valid_ifd && type == def_type && ( count == def_count || def_count == ExifTag.SIZE_UNDEFINED ) ){
ret = i;
break;
}
}
return ret;
}
-
+
/**
* Removes a tag definition for given defined tag constant.
*
* @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
*/
- @SuppressWarnings( "unused" )
- public void removeTagDefinition( int tagId ) {
+ @SuppressWarnings("unused")
+ public void removeTagDefinition( int tagId ){
getTagInfo().delete( tagId );
}
-
+
/**
* Resets tag definitions to the default ones.
*/
- @SuppressWarnings( "unused" )
- public void resetTagDefinitions() {
+ @SuppressWarnings("unused")
+ public void resetTagDefinitions(){
mTagInfo = null;
}
-
+
/**
* Returns the thumbnail from IFD1 as a bitmap, or null if none exists.
*
* @return the thumbnail as a bitmap.
*/
- public Bitmap getThumbnailBitmap() {
- if( mData.hasCompressedThumbnail() ) {
+ public Bitmap getThumbnailBitmap(){
+ if( mData.hasCompressedThumbnail() ){
byte[] thumb = mData.getCompressedThumbnail();
return BitmapFactory.decodeByteArray( thumb, 0, thumb.length );
- }
- else if( mData.hasUncompressedStrip() ) {
+ }else if( mData.hasUncompressedStrip() ){
// TODO: implement uncompressed
+ return null;
+ }else{
+ return null;
}
- return null;
}
-
+
/**
* Returns the thumbnail from IFD1 as a byte array, or null if none exists.
* The bytes may either be an uncompressed strip as specified in the exif
@@ -1962,36 +1958,37 @@ else if( mData.hasUncompressedStrip() ) {
*
* @return the thumbnail as a byte array.
*/
- @SuppressWarnings( "unused" )
- public byte[] getThumbnailBytes() {
- if( mData.hasCompressedThumbnail() ) {
+ @SuppressWarnings("unused")
+ public byte[] getThumbnailBytes(){
+ if( mData.hasCompressedThumbnail() ){
return mData.getCompressedThumbnail();
- }
- else if( mData.hasUncompressedStrip() ) {
+ }else if( mData.hasUncompressedStrip() ){
// TODO: implement this
+ return null;
+ }else{
+ return null;
}
- return null;
}
-
+
/**
* Returns the thumbnail if it is jpeg compressed, or null if none exists.
*
* @return the thumbnail as a byte array.
*/
- public byte[] getThumbnail() {
+ public byte[] getThumbnail(){
return mData.getCompressedThumbnail();
}
-
+
/**
* Returns the JPEG quality used to generate the image
* or 0 if not found
*
* @return
*/
- public int getQualityGuess() {
+ public int getQualityGuess(){
return mData.getQualityGuess();
}
-
+
/**
* this gives information about the process used to create the JPEG file.
* Possible values are:
@@ -2012,37 +2009,37 @@ public int getQualityGuess() {
* '207' Differential lossless, arithmetic coding
*
*/
- public short getJpegProcess() {
+ public short getJpegProcess(){
return mData.getJpegProcess();
}
-
+
/**
* Returns the Image size as decoded from the SOF marker
*/
- public int[] getImageSize() {
+ public int[] getImageSize(){
return mData.getImageSize();
}
-
+
/**
* Check if thumbnail is compressed.
*
* @return true if the thumbnail is compressed.
*/
- @SuppressWarnings( "unused" )
- public boolean isThumbnailCompressed() {
+ @SuppressWarnings("unused")
+ public boolean isThumbnailCompressed(){
return mData.hasCompressedThumbnail();
}
-
+
/**
* Check if thumbnail exists.
*
* @return true if a compressed thumbnail exists.
*/
- public boolean hasThumbnail() {
+ public boolean hasThumbnail(){
// TODO: add back in uncompressed strip
return mData.hasCompressedThumbnail();
}
-
+
/**
* Sets the thumbnail to be a jpeg compressed bitmap. Clears any prior
* thumbnail.
@@ -2050,15 +2047,15 @@ public boolean hasThumbnail() {
* @param thumb a bitmap to compress to a jpeg thumbnail.
* @return true if the thumbnail was set.
*/
- @SuppressWarnings( "unused" )
- public boolean setCompressedThumbnail( Bitmap thumb ) {
+ @SuppressWarnings("unused")
+ public boolean setCompressedThumbnail( Bitmap thumb ){
ByteArrayOutputStream thumbnail = new ByteArrayOutputStream();
- if( ! thumb.compress( Bitmap.CompressFormat.JPEG, 90, thumbnail ) ) {
+ if( ! thumb.compress( Bitmap.CompressFormat.JPEG, 90, thumbnail ) ){
return false;
}
return setCompressedThumbnail( thumbnail.toByteArray() );
}
-
+
/**
* Sets the thumbnail to be a jpeg compressed image. Clears any prior
* thumbnail.
@@ -2066,53 +2063,53 @@ public boolean setCompressedThumbnail( Bitmap thumb ) {
* @param thumb a byte array containing a jpeg compressed image.
* @return true if the thumbnail was set.
*/
- public boolean setCompressedThumbnail( byte[] thumb ) {
+ public boolean setCompressedThumbnail( byte[] thumb ){
mData.clearThumbnailAndStrips();
mData.setCompressedThumbnail( thumb );
return true;
}
-
+
/**
* Clears the compressed thumbnail if it exists.
*/
- @SuppressWarnings( "unused" )
- public void removeCompressedThumbnail() {
+ @SuppressWarnings("unused")
+ public void removeCompressedThumbnail(){
mData.setCompressedThumbnail( null );
}
-
+
/**
* Decodes the user comment tag into string as specified in the EXIF
* standard. Returns null if decoding failed.
*/
- @SuppressWarnings( "unused" )
- public String getUserComment() {
+ @SuppressWarnings("unused")
+ public String getUserComment(){
return mData.getUserComment();
}
-
+
/**
* Return the altitude in meters. If the exif tag does not exist, return
* defaultValue.
*
* @param defaultValue the value to return if the tag is not available.
*/
- @SuppressWarnings( "unused" )
- public double getAltitude( double defaultValue ) {
-
+ @SuppressWarnings("unused")
+ public double getAltitude( double defaultValue ){
+
Byte ref = getTagByteValue( TAG_GPS_ALTITUDE_REF );
Rational gpsAltitude = getTagRationalValue( TAG_GPS_ALTITUDE );
-
+
int seaLevel = 1;
- if( null != ref ) {
+ if( null != ref ){
seaLevel = ref.intValue() == 1 ? - 1 : 1;
}
-
- if( gpsAltitude != null ) {
+
+ if( gpsAltitude != null ){
return gpsAltitude.toDouble() * seaLevel;
}
-
+
return defaultValue;
}
-
+
/**
* Gets the GPS latitude and longitude as a pair of doubles from this
* ExifInterface object's tags, or null if the necessary tags do not exist.
@@ -2121,85 +2118,86 @@ public double getAltitude( double defaultValue ) {
* respectively.
* @see #convertLatOrLongToDouble
*/
- public double[] getLatLongAsDoubles() {
+ public double[] getLatLongAsDoubles(){
Rational[] latitude = getTagRationalValues( TAG_GPS_LATITUDE );
String latitudeRef = getTagStringValue( TAG_GPS_LATITUDE_REF );
Rational[] longitude = getTagRationalValues( TAG_GPS_LONGITUDE );
String longitudeRef = getTagStringValue( TAG_GPS_LONGITUDE_REF );
- if( latitude == null || longitude == null || latitudeRef == null || longitudeRef == null || latitude.length < 3 || longitude.length < 3 ) {
+ if( latitude == null || longitude == null || latitudeRef == null || longitudeRef == null || latitude.length < 3 || longitude.length < 3 ){
return null;
}
- double[] latLon = new double[2];
- latLon[0] = convertLatOrLongToDouble( latitude, latitudeRef );
- latLon[1] = convertLatOrLongToDouble( longitude, longitudeRef );
+ double[] latLon = new double[ 2 ];
+ latLon[ 0 ] = convertLatOrLongToDouble( latitude, latitudeRef );
+ latLon[ 1 ] = convertLatOrLongToDouble( longitude, longitudeRef );
return latLon;
}
-
+
/**
* Returns a formatted String with the latitude representation:
* 39° 8' 16.8" N
*/
- public String getLatitude() {
+ public String getLatitude(){
Rational[] latitude = getTagRationalValues( TAG_GPS_LATITUDE );
String latitudeRef = getTagStringValue( TAG_GPS_LATITUDE_REF );
-
+
if( null == latitude || null == latitudeRef ) return null;
return convertRationalLatLonToString( latitude, latitudeRef );
}
-
+
/**
* Returns a formatted String with the longitude representation:
* 77° 37' 51.6" W
*/
- public String getLongitude() {
+ public String getLongitude(){
Rational[] longitude = getTagRationalValues( TAG_GPS_LONGITUDE );
String longitudeRef = getTagStringValue( TAG_GPS_LONGITUDE_REF );
-
+
if( null == longitude || null == longitudeRef ) return null;
return convertRationalLatLonToString( longitude, longitudeRef );
}
-
- private static String convertRationalLatLonToString( Rational[] coord, String ref ) {
- try {
-
- double degrees = coord[0].toDouble();
- double minutes = coord[1].toDouble();
- double seconds = coord[2].toDouble();
+
+ private static String convertRationalLatLonToString( Rational[] coord, String ref ){
+ try{
+
+ double degrees = coord[ 0 ].toDouble();
+ double minutes = coord[ 1 ].toDouble();
+ double seconds = coord[ 2 ].toDouble();
ref = ref.substring( 0, 1 );
-
+
return String.format( "%1$.0f° %2$.0f' %3$.0f\" %4$s", degrees, minutes, seconds, ref.toUpperCase( Locale.getDefault() ) );
- } catch( NumberFormatException e ) {
+ }catch( NumberFormatException e ){
e.printStackTrace();
- } catch( ArrayIndexOutOfBoundsException e ) {
+ }catch( ArrayIndexOutOfBoundsException e ){
e.printStackTrace();
}
return null;
}
-
+
/**
* Given an exif date time, like {@link #TAG_DATE_TIME} or {@link #TAG_DATE_TIME_DIGITIZED}
* returns a java Date object
*
* @param dateTimeString one of the value of {@link #TAG_DATE_TIME} or {@link #TAG_DATE_TIME_DIGITIZED}
- * @param timeZone the target timezone
+ * @param timeZone the target timezone
* @return the parsed date
*/
- public static Date getDateTime( String dateTimeString, TimeZone timeZone ) {
+ public static Date getDateTime( String dateTimeString, TimeZone timeZone ){
if( dateTimeString == null ) return null;
-
+
+ @SuppressLint("SimpleDateFormat")
DateFormat formatter = new SimpleDateFormat( DATETIME_FORMAT_STR );
formatter.setTimeZone( timeZone );
-
- try {
+
+ try{
return formatter.parse( dateTimeString );
- } catch( IllegalArgumentException e ) {
+ }catch( IllegalArgumentException e ){
e.printStackTrace();
- } catch( ParseException e ) {
+ }catch( ParseException e ){
e.printStackTrace();
}
return null;
}
-
+
/**
* Creates, formats, and sets the DateTimeStamp tag for one of:
* {@link #TAG_DATE_TIME}, {@link #TAG_DATE_TIME_DIGITIZED},
@@ -2210,21 +2208,20 @@ public static Date getDateTime( String dateTimeString, TimeZone timeZone ) {
* @param timezone a TimeZone object.
* @return true if success, false if the tag could not be set.
*/
- public boolean addDateTimeStampTag( int tagId, long timestamp, TimeZone timezone ) {
- if( tagId == TAG_DATE_TIME || tagId == TAG_DATE_TIME_DIGITIZED || tagId == TAG_DATE_TIME_ORIGINAL ) {
+ public boolean addDateTimeStampTag( int tagId, long timestamp, TimeZone timezone ){
+ if( tagId == TAG_DATE_TIME || tagId == TAG_DATE_TIME_DIGITIZED || tagId == TAG_DATE_TIME_ORIGINAL ){
mDateTimeStampFormat.setTimeZone( timezone );
ExifTag t = buildTag( tagId, mDateTimeStampFormat.format( timestamp ) );
- if( t == null ) {
+ if( t == null ){
return false;
}
setTag( t );
- }
- else {
+ }else{
return false;
}
return true;
}
-
+
/**
* Creates a tag for a defined tag constant in the tag's default IFD.
*
@@ -2232,11 +2229,11 @@ public boolean addDateTimeStampTag( int tagId, long timestamp, TimeZone timezone
* @param val the tag's value.
* @return an ExifTag object.
*/
- public ExifTag buildTag( int tagId, Object val ) {
+ public ExifTag buildTag( int tagId, Object val ){
int ifdId = getTrueIfd( tagId );
return buildTag( tagId, ifdId, val );
}
-
+
/**
* Creates a tag for a defined tag constant in a given IFD if that IFD is
* allowed for the tag. This method will fail anytime the appropriate
@@ -2248,39 +2245,39 @@ public ExifTag buildTag( int tagId, Object val ) {
* @return an ExifTag object or null if one could not be constructed.
* @see #buildTag
*/
- public ExifTag buildTag( int tagId, int ifdId, Object val ) {
+ public ExifTag buildTag( int tagId, int ifdId, Object val ){
int info = getTagInfo().get( tagId );
- if( info == 0 || val == null ) {
+ if( info == 0 || val == null ){
return null;
}
short type = getTypeFromInfo( info );
int definedCount = getComponentCountFromInfo( info );
boolean hasDefinedCount = ( definedCount != ExifTag.SIZE_UNDEFINED );
- if( ! ExifInterface.isIfdAllowed( info, ifdId ) ) {
+ if( ! ExifInterface.isIfdAllowed( info, ifdId ) ){
return null;
}
ExifTag t = new ExifTag( getTrueTagKey( tagId ), type, definedCount, ifdId, hasDefinedCount );
- if( ! t.setValue( val ) ) {
+ if( ! t.setValue( val ) ){
return null;
}
return t;
}
-
- protected static boolean isIfdAllowed( int info, int ifd ) {
+
+ protected static boolean isIfdAllowed( int info, int ifd ){
int[] ifds = IfdData.getIfds();
int ifdFlags = getAllowedIfdFlagsFromInfo( info );
- for( int i = 0; i < ifds.length; i++ ) {
- if( ifd == ifds[i] && ( ( ifdFlags >> i ) & 1 ) == 1 ) {
+ for( int i = 0 ; i < ifds.length ; i++ ){
+ if( ifd == ifds[ i ] && ( ( ifdFlags >> i ) & 1 ) == 1 ){
return true;
}
}
return false;
}
-
- protected static int getAllowedIfdFlagsFromInfo( int info ) {
+
+ protected static int getAllowedIfdFlagsFromInfo( int info ){
return info >>> 24;
}
-
+
/**
* Creates and sets all to the GPS tags for a give latitude and longitude.
*
@@ -2288,13 +2285,13 @@ protected static int getAllowedIfdFlagsFromInfo( int info ) {
* @param longitude a GPS longitude coordinate.
* @return true if success, false if they could not be created or set.
*/
- @SuppressWarnings( "unused" )
- public boolean addGpsTags( double latitude, double longitude ) {
+ @SuppressWarnings("unused")
+ public boolean addGpsTags( double latitude, double longitude ){
ExifTag latTag = buildTag( TAG_GPS_LATITUDE, toExifLatLong( latitude ) );
ExifTag longTag = buildTag( TAG_GPS_LONGITUDE, toExifLatLong( longitude ) );
ExifTag latRefTag = buildTag( TAG_GPS_LATITUDE_REF, latitude >= 0 ? GpsLatitudeRef.NORTH : GpsLatitudeRef.SOUTH );
ExifTag longRefTag = buildTag( TAG_GPS_LONGITUDE_REF, longitude >= 0 ? GpsLongitudeRef.EAST : GpsLongitudeRef.WEST );
- if( latTag == null || longTag == null || latRefTag == null || longRefTag == null ) {
+ if( latTag == null || longTag == null || latRefTag == null || longRefTag == null ){
return false;
}
setTag( latTag );
@@ -2303,8 +2300,8 @@ public boolean addGpsTags( double latitude, double longitude ) {
setTag( longRefTag );
return true;
}
-
- private static Rational[] toExifLatLong( double value ) {
+
+ private static Rational[] toExifLatLong( double value ){
// convert to the format dd/1 mm/1 ssss/100
value = Math.abs( value );
int degrees = (int) value;
@@ -2314,64 +2311,64 @@ private static Rational[] toExifLatLong( double value ) {
int seconds = (int) value;
return new Rational[]{ new Rational( degrees, 1 ), new Rational( minutes, 1 ), new Rational( seconds, 100 ) };
}
-
+
/**
* Creates and sets the GPS timestamp tag.
*
* @param timestamp a GPS timestamp.
* @return true if success, false if could not be created or set.
*/
- @SuppressWarnings( "unused" )
- public boolean addGpsDateTimeStampTag( long timestamp ) {
+ @SuppressWarnings("unused")
+ public boolean addGpsDateTimeStampTag( long timestamp ){
ExifTag t = buildTag( TAG_GPS_DATE_STAMP, mGPSDateStampFormat.format( timestamp ) );
- if( t == null ) {
+ if( t == null ){
return false;
}
setTag( t );
mGPSTimeStampCalendar.setTimeInMillis( timestamp );
t = buildTag( TAG_GPS_TIME_STAMP,
- new Rational[]{ new Rational( mGPSTimeStampCalendar.get( Calendar.HOUR_OF_DAY ), 1 ), new Rational( mGPSTimeStampCalendar.get( Calendar.MINUTE ), 1 ),
- new Rational( mGPSTimeStampCalendar.get( Calendar.SECOND ), 1 ) }
+ new Rational[]{ new Rational( mGPSTimeStampCalendar.get( Calendar.HOUR_OF_DAY ), 1 ), new Rational( mGPSTimeStampCalendar.get( Calendar.MINUTE ), 1 ),
+ new Rational( mGPSTimeStampCalendar.get( Calendar.SECOND ), 1 ) }
);
- if( t == null ) {
+ if( t == null ){
return false;
}
setTag( t );
return true;
}
-
+
/**
* Return the aperture size, if present, 0 if missing
*/
- public double getApertureSize() {
+ public double getApertureSize(){
Rational rational = getTagRationalValue( TAG_F_NUMBER );
- if( null != rational && rational.toDouble() > 0 ) {
+ if( null != rational && rational.toDouble() > 0 ){
return rational.toDouble();
}
-
+
rational = getTagRationalValue( TAG_APERTURE_VALUE );
- if( null != rational && rational.toDouble() > 0 ) {
+ if( null != rational && rational.toDouble() > 0 ){
return Math.exp( rational.toDouble() * Math.log( 2 ) * 0.5 );
}
return 0;
}
-
+
/**
* Returns the lens model as string if any of the tags {@link #TAG_LENS_MODEL}
* or {@link #TAG_LENS_SPECS} are found
*
* @return the string representation of the lens spec
*/
- public String getLensModelDescription() {
+ public String getLensModelDescription(){
String lensModel = getTagStringValue( TAG_LENS_MODEL );
if( null != lensModel ) return lensModel;
-
+
Rational[] rat = getTagRationalValues( TAG_LENS_SPECS );
if( null != rat ) return ExifUtil.processLensSpecifications( rat );
-
+
return null;
}
-
+
/**
* Constants for {@link #TAG_ORIENTATION}. They can be interpreted as
* follows:
@@ -2386,444 +2383,468 @@ public String getLensModelDescription() {
* RIGHT_BOTTOM is a 270 degree clockwise rotation.
*
*/
- @SuppressWarnings( "unused" )
- public static interface Orientation {
- public static final short TOP_LEFT = 1;
- public static final short TOP_RIGHT = 2;
- public static final short BOTTOM_RIGHT = 3;
- public static final short BOTTOM_LEFT = 4;
- public static final short LEFT_TOP = 5;
- public static final short RIGHT_TOP = 6;
- public static final short RIGHT_BOTTOM = 7;
- public static final short LEFT_BOTTOM = 8;
+ @SuppressWarnings("unused")
+ public interface Orientation {
+ short TOP_LEFT = 1;
+ short TOP_RIGHT = 2;
+ short BOTTOM_RIGHT = 3;
+ short BOTTOM_LEFT = 4;
+ short LEFT_TOP = 5;
+ short RIGHT_TOP = 6;
+ short RIGHT_BOTTOM = 7;
+ short LEFT_BOTTOM = 8;
}
-
+
/**
* Constants for {@link #TAG_Y_CB_CR_POSITIONING}
*/
- @SuppressWarnings( "unused" )
- public static interface YCbCrPositioning {
- public static final short CENTERED = 1;
- public static final short CO_SITED = 2;
+ @SuppressWarnings("unused")
+ public interface YCbCrPositioning {
+ short CENTERED = 1;
+ short CO_SITED = 2;
}
-
+
/**
* Constants for {@link #TAG_COMPRESSION}
*/
- @SuppressWarnings( "unused" )
- public static interface Compression {
- public static final short UNCOMPRESSION = 1;
- public static final short JPEG = 6;
+ @SuppressWarnings("unused")
+ public interface Compression {
+ short UNCOMPRESSION = 1;
+ short JPEG = 6;
}
-
+
// TODO: uncompressed thumbnail setters
-
+
/**
* Constants for {@link #TAG_RESOLUTION_UNIT}
*/
- @SuppressWarnings( "unused" )
- public static interface ResolutionUnit {
- public static final short INCHES = 2;
- public static final short CENTIMETERS = 3;
- public static final short MILLIMETERS = 4;
- public static final short MICROMETERS = 5;
+ @SuppressWarnings("unused")
+ public interface ResolutionUnit {
+ short INCHES = 2;
+ short CENTIMETERS = 3;
+ short MILLIMETERS = 4;
+ short MICROMETERS = 5;
}
-
+
/**
* Constants for {@link #TAG_PHOTOMETRIC_INTERPRETATION}
*/
- @SuppressWarnings( "unused" )
- public static interface PhotometricInterpretation {
- public static final short RGB = 2;
- public static final short YCBCR = 6;
+ @SuppressWarnings("unused")
+ public interface PhotometricInterpretation {
+ short RGB = 2;
+ short YCBCR = 6;
}
-
+
/**
* Constants for {@link #TAG_PLANAR_CONFIGURATION}
*/
- @SuppressWarnings( "unused" )
- public static interface PlanarConfiguration {
- public static final short CHUNKY = 1;
- public static final short PLANAR = 2;
+ @SuppressWarnings("unused")
+ public interface PlanarConfiguration {
+ short CHUNKY = 1;
+ short PLANAR = 2;
}
-
+
// Convenience methods:
-
+
/**
* Constants for {@link #TAG_EXPOSURE_PROGRAM}
*/
- @SuppressWarnings( "unused" )
- public static interface ExposureProgram {
- public static final short NOT_DEFINED = 0;
- public static final short MANUAL = 1;
- public static final short NORMAL_PROGRAM = 2;
- public static final short APERTURE_PRIORITY = 3;
- public static final short SHUTTER_PRIORITY = 4;
- public static final short CREATIVE_PROGRAM = 5;
- public static final short ACTION_PROGRAM = 6;
- public static final short PROTRAIT_MODE = 7;
- public static final short LANDSCAPE_MODE = 8;
+ @SuppressWarnings("unused")
+ public interface ExposureProgram {
+ short NOT_DEFINED = 0;
+ short MANUAL = 1;
+ short NORMAL_PROGRAM = 2;
+ short APERTURE_PRIORITY = 3;
+ short SHUTTER_PRIORITY = 4;
+ short CREATIVE_PROGRAM = 5;
+ short ACTION_PROGRAM = 6;
+ short PROTRAIT_MODE = 7;
+ short LANDSCAPE_MODE = 8;
}
-
+
/**
* Constants for {@link #TAG_METERING_MODE}
*/
- @SuppressWarnings( "unused" )
- public static interface MeteringMode {
- public static final short UNKNOWN = 0;
- public static final short AVERAGE = 1;
- public static final short CENTER_WEIGHTED_AVERAGE = 2;
- public static final short SPOT = 3;
- public static final short MULTISPOT = 4;
- public static final short PATTERN = 5;
- public static final short PARTAIL = 6;
- public static final short OTHER = 255;
- }
-
- @SuppressWarnings( "unused" )
- public static byte[] toBitArray( short value ) {
- byte[] result = new byte[16];
- for( int i = 0; i < 16; i++ ) {
- result[15 - i] = (byte) ( ( value >> i ) & 1 );
+ @SuppressWarnings("unused")
+ public interface MeteringMode {
+ short UNKNOWN = 0;
+ short AVERAGE = 1;
+ short CENTER_WEIGHTED_AVERAGE = 2;
+ short SPOT = 3;
+ short MULTISPOT = 4;
+ short PATTERN = 5;
+ short PARTAIL = 6;
+ short OTHER = 255;
+ }
+
+ @SuppressWarnings("unused")
+ public static byte[] toBitArray( short value ){
+ byte[] result = new byte[ 16 ];
+ for( int i = 0 ; i < 16 ; i++ ){
+ result[ 15 - i ] = (byte) ( ( value >> i ) & 1 );
}
return result;
}
-
+
/**
* Constants for {@link #TAG_FLASH} As the definition in Jeita EXIF 2.2
*/
- @SuppressWarnings( "unused" )
- public static interface Flash {
-
- /** first bit */
- public static enum FlashFired {
+ @SuppressWarnings("unused")
+ public interface Flash {
+
+ /**
+ * first bit
+ */
+ enum FlashFired {
NO, YES
}
-
- /** Values for bits 1 and 2 indicating the status of returned light */
- public static enum StrobeLightDetection {
+
+ /**
+ * Values for bits 1 and 2 indicating the status of returned light
+ */
+ enum StrobeLightDetection {
NO_DETECTION, RESERVED, LIGHT_NOT_DETECTED, LIGHT_DETECTED
}
-
- /** Values for bits 3 and 4 indicating the camera's flash mode */
- public static enum CompulsoryMode {
+
+ /**
+ * Values for bits 3 and 4 indicating the camera's flash mode
+ */
+ enum CompulsoryMode {
UNKNOWN,
FIRING,
SUPPRESSION,
AUTO
}
-
- /** Values for bit 5 indicating the presence of a flash function. */
- public static enum FlashFunction {
+
+ /**
+ * Values for bit 5 indicating the presence of a flash function.
+ */
+ enum FlashFunction {
FUNCTION_PRESENT,
FUNCTION_NOR_PRESENT
}
-
- /** Values for bit 6 indicating the camera's red-eye mode. */
- public static enum RedEyeMode {
+
+ /**
+ * Values for bit 6 indicating the camera's red-eye mode.
+ */
+ enum RedEyeMode {
NONE,
SUPPORTED
}
}
-
+
/**
* Constants for {@link #TAG_COLOR_SPACE}
*/
- @SuppressWarnings( "unused" )
- public static interface ColorSpace {
- public static final short SRGB = 1;
- public static final short UNCALIBRATED = (short) 0xFFFF;
+ @SuppressWarnings("unused")
+ public interface ColorSpace {
+ short SRGB = 1;
+ short UNCALIBRATED = (short) 0xFFFF;
}
-
+
/**
* Constants for {@link #TAG_EXPOSURE_MODE}
*/
- @SuppressWarnings( "unused" )
- public static interface ExposureMode {
- public static final short AUTO_EXPOSURE = 0;
- public static final short MANUAL_EXPOSURE = 1;
- public static final short AUTO_BRACKET = 2;
+ @SuppressWarnings("unused")
+ public interface ExposureMode {
+ short AUTO_EXPOSURE = 0;
+ short MANUAL_EXPOSURE = 1;
+ short AUTO_BRACKET = 2;
}
-
+
/**
* Constants for {@link #TAG_WHITE_BALANCE}
*/
- @SuppressWarnings( "unused" )
- public static interface WhiteBalance {
- public static final short AUTO = 0;
- public static final short MANUAL = 1;
+ @SuppressWarnings("unused")
+ public interface WhiteBalance {
+ short AUTO = 0;
+ short MANUAL = 1;
}
-
+
/**
* Constants for {@link #TAG_SCENE_CAPTURE_TYPE}
*/
- @SuppressWarnings( "unused" )
- public static interface SceneCapture {
- public static final short STANDARD = 0;
- public static final short LANDSCAPE = 1;
- public static final short PROTRAIT = 2;
- public static final short NIGHT_SCENE = 3;
+ @SuppressWarnings("unused")
+ public interface SceneCapture {
+ short STANDARD = 0;
+ short LANDSCAPE = 1;
+ short PROTRAIT = 2;
+ short NIGHT_SCENE = 3;
}
-
+
/**
* Constants for {@link #TAG_COMPONENTS_CONFIGURATION}
*/
- @SuppressWarnings( "unused" )
- public static interface ComponentsConfiguration {
- public static final short NOT_EXIST = 0;
- public static final short Y = 1;
- public static final short CB = 2;
- public static final short CR = 3;
- public static final short R = 4;
- public static final short G = 5;
- public static final short B = 6;
+ @SuppressWarnings("unused")
+ public interface ComponentsConfiguration {
+ short NOT_EXIST = 0;
+ short Y = 1;
+ short CB = 2;
+ short CR = 3;
+ short R = 4;
+ short G = 5;
+ short B = 6;
}
-
+
/**
* Constants for {@link #TAG_LIGHT_SOURCE}
*/
- @SuppressWarnings( "unused" )
- public static interface LightSource {
- public static final short UNKNOWN = 0;
- public static final short DAYLIGHT = 1;
- public static final short FLUORESCENT = 2;
- public static final short TUNGSTEN = 3;
- public static final short FLASH = 4;
- public static final short FINE_WEATHER = 9;
- public static final short CLOUDY_WEATHER = 10;
- public static final short SHADE = 11;
- public static final short DAYLIGHT_FLUORESCENT = 12;
- public static final short DAY_WHITE_FLUORESCENT = 13;
- public static final short COOL_WHITE_FLUORESCENT = 14;
- public static final short WHITE_FLUORESCENT = 15;
- public static final short STANDARD_LIGHT_A = 17;
- public static final short STANDARD_LIGHT_B = 18;
- public static final short STANDARD_LIGHT_C = 19;
- public static final short D55 = 20;
- public static final short D65 = 21;
- public static final short D75 = 22;
- public static final short D50 = 23;
- public static final short ISO_STUDIO_TUNGSTEN = 24;
- public static final short OTHER = 255;
- }
-
+ @SuppressWarnings("unused")
+ public interface LightSource {
+ short UNKNOWN = 0;
+ short DAYLIGHT = 1;
+ short FLUORESCENT = 2;
+ short TUNGSTEN = 3;
+ short FLASH = 4;
+ short FINE_WEATHER = 9;
+ short CLOUDY_WEATHER = 10;
+ short SHADE = 11;
+ short DAYLIGHT_FLUORESCENT = 12;
+ short DAY_WHITE_FLUORESCENT = 13;
+ short COOL_WHITE_FLUORESCENT = 14;
+ short WHITE_FLUORESCENT = 15;
+ short STANDARD_LIGHT_A = 17;
+ short STANDARD_LIGHT_B = 18;
+ short STANDARD_LIGHT_C = 19;
+ short D55 = 20;
+ short D65 = 21;
+ short D75 = 22;
+ short D50 = 23;
+ short ISO_STUDIO_TUNGSTEN = 24;
+ short OTHER = 255;
+ }
+
/**
* Constants for {@link #TAG_SENSING_METHOD}
*/
- @SuppressWarnings( "unused" )
- public static interface SensingMethod {
- public static final short NOT_DEFINED = 1;
- public static final short ONE_CHIP_COLOR = 2;
- public static final short TWO_CHIP_COLOR = 3;
- public static final short THREE_CHIP_COLOR = 4;
- public static final short COLOR_SEQUENTIAL_AREA = 5;
- public static final short TRILINEAR = 7;
- public static final short COLOR_SEQUENTIAL_LINEAR = 8;
+ @SuppressWarnings("unused")
+ public interface SensingMethod {
+ short NOT_DEFINED = 1;
+ short ONE_CHIP_COLOR = 2;
+ short TWO_CHIP_COLOR = 3;
+ short THREE_CHIP_COLOR = 4;
+ short COLOR_SEQUENTIAL_AREA = 5;
+ short TRILINEAR = 7;
+ short COLOR_SEQUENTIAL_LINEAR = 8;
}
-
+
/**
* Constants for {@link #TAG_FILE_SOURCE}
*/
- @SuppressWarnings( "unused" )
- public static interface FileSource {
- public static final short DSC = 3;
+ @SuppressWarnings("unused")
+ public interface FileSource {
+ short DSC = 3;
}
-
+
/**
* Constants for {@link #TAG_SCENE_TYPE}
*/
- @SuppressWarnings( "unused" )
- public static interface SceneType {
- public static final short DIRECT_PHOTOGRAPHED = 1;
+ @SuppressWarnings("unused")
+ public interface SceneType {
+ short DIRECT_PHOTOGRAPHED = 1;
}
-
+
/**
* Constants for {@link #TAG_GAIN_CONTROL}
*/
- @SuppressWarnings( "unused" )
- public static interface GainControl {
- public static final short NONE = 0;
- public static final short LOW_UP = 1;
- public static final short HIGH_UP = 2;
- public static final short LOW_DOWN = 3;
- public static final short HIGH_DOWN = 4;
+ @SuppressWarnings("unused")
+ public interface GainControl {
+ short NONE = 0;
+ short LOW_UP = 1;
+ short HIGH_UP = 2;
+ short LOW_DOWN = 3;
+ short HIGH_DOWN = 4;
}
-
+
/**
* Constants for {@link #TAG_CONTRAST}
*/
- @SuppressWarnings( "unused" )
- public static interface Contrast {
- public static final short NORMAL = 0;
- public static final short SOFT = 1;
- public static final short HARD = 2;
+ @SuppressWarnings("unused")
+ public interface Contrast {
+ short NORMAL = 0;
+ short SOFT = 1;
+ short HARD = 2;
}
-
+
/**
* Constants for {@link #TAG_SATURATION}
*/
- @SuppressWarnings( "unused" )
- public static interface Saturation {
- public static final short NORMAL = 0;
- public static final short LOW = 1;
- public static final short HIGH = 2;
+ @SuppressWarnings("unused")
+ public interface Saturation {
+ short NORMAL = 0;
+ short LOW = 1;
+ short HIGH = 2;
}
-
+
/**
* Constants for {@link #TAG_SHARPNESS}
*/
- @SuppressWarnings( "unused" )
- public static interface Sharpness {
- public static final short NORMAL = 0;
- public static final short SOFT = 1;
- public static final short HARD = 2;
+ @SuppressWarnings("unused")
+ public interface Sharpness {
+ short NORMAL = 0;
+ short SOFT = 1;
+ short HARD = 2;
}
-
+
/**
* Constants for {@link #TAG_SUBJECT_DISTANCE}
*/
- @SuppressWarnings( "unused" )
- public static interface SubjectDistance {
- public static final short UNKNOWN = 0;
- public static final short MACRO = 1;
- public static final short CLOSE_VIEW = 2;
- public static final short DISTANT_VIEW = 3;
+ @SuppressWarnings("unused")
+ public interface SubjectDistance {
+ short UNKNOWN = 0;
+ short MACRO = 1;
+ short CLOSE_VIEW = 2;
+ short DISTANT_VIEW = 3;
}
-
+
/**
* Constants for {@link #TAG_GPS_LATITUDE_REF},
* {@link #TAG_GPS_DEST_LATITUDE_REF}
*/
- @SuppressWarnings( "unused" )
- public static interface GpsLatitudeRef {
- public static final String NORTH = "N";
- public static final String SOUTH = "S";
+ @SuppressWarnings("unused")
+ public interface GpsLatitudeRef {
+ String NORTH = "N";
+ String SOUTH = "S";
}
-
+
/**
* Constants for {@link #TAG_GPS_LONGITUDE_REF},
* {@link #TAG_GPS_DEST_LONGITUDE_REF}
*/
- @SuppressWarnings( "unused" )
- public static interface GpsLongitudeRef {
- public static final String EAST = "E";
- public static final String WEST = "W";
+ @SuppressWarnings("unused")
+ public interface GpsLongitudeRef {
+ String EAST = "E";
+ String WEST = "W";
}
-
+
/**
* Constants for {@link #TAG_GPS_ALTITUDE_REF}
*/
- @SuppressWarnings( "unused" )
- public static interface GpsAltitudeRef {
- public static final short SEA_LEVEL = 0;
- public static final short SEA_LEVEL_NEGATIVE = 1;
+ @SuppressWarnings("unused")
+ public interface GpsAltitudeRef {
+ short SEA_LEVEL = 0;
+ short SEA_LEVEL_NEGATIVE = 1;
}
-
+
/**
* Constants for {@link #TAG_GPS_STATUS}
*/
- @SuppressWarnings( "unused" )
- public static interface GpsStatus {
- public static final String IN_PROGRESS = "A";
- public static final String INTEROPERABILITY = "V";
+ @SuppressWarnings("unused")
+ public interface GpsStatus {
+ String IN_PROGRESS = "A";
+ String INTEROPERABILITY = "V";
}
-
+
/**
* Constants for {@link #TAG_GPS_MEASURE_MODE}
*/
- @SuppressWarnings( "unused" )
- public static interface GpsMeasureMode {
- public static final String MODE_2_DIMENSIONAL = "2";
- public static final String MODE_3_DIMENSIONAL = "3";
+ @SuppressWarnings("unused")
+ public interface GpsMeasureMode {
+ String MODE_2_DIMENSIONAL = "2";
+ String MODE_3_DIMENSIONAL = "3";
}
-
+
/**
* Constants for {@link #TAG_GPS_SPEED_REF},
* {@link #TAG_GPS_DEST_DISTANCE_REF}
*/
- @SuppressWarnings( "unused" )
- public static interface GpsSpeedRef {
- public static final String KILOMETERS = "K";
- public static final String MILES = "M";
- public static final String KNOTS = "N";
+ @SuppressWarnings("unused")
+ public interface GpsSpeedRef {
+ String KILOMETERS = "K";
+ String MILES = "M";
+ String KNOTS = "N";
}
-
+
/**
* Constants for {@link #TAG_GPS_TRACK_REF},
* {@link #TAG_GPS_IMG_DIRECTION_REF}, {@link #TAG_GPS_DEST_BEARING_REF}
*/
- @SuppressWarnings( "unused" )
- public static interface GpsTrackRef {
- public static final String TRUE_DIRECTION = "T";
- public static final String MAGNETIC_DIRECTION = "M";
+ @SuppressWarnings("unused")
+ public interface GpsTrackRef {
+ String TRUE_DIRECTION = "T";
+ String MAGNETIC_DIRECTION = "M";
}
-
+
/**
* Constants for {@link #TAG_GPS_DIFFERENTIAL}
*/
- @SuppressWarnings( "unused" )
- public static interface GpsDifferential {
- public static final short WITHOUT_DIFFERENTIAL_CORRECTION = 0;
- public static final short DIFFERENTIAL_CORRECTION_APPLIED = 1;
+ @SuppressWarnings("unused")
+ public interface GpsDifferential {
+ short WITHOUT_DIFFERENTIAL_CORRECTION = 0;
+ short DIFFERENTIAL_CORRECTION_APPLIED = 1;
}
-
+
/**
* Constants for the jpeg process algorithm used.
*
* @see #getJpegProcess()
*/
- @SuppressWarnings( "unused" )
- public static interface JpegProcess {
- public static final short BASELINE = (short) 0xFFC0;
- public static final short EXTENDED_SEQUENTIAL = (short) 0xFFC1;
- public static final short PROGRESSIVE = (short) 0xFFC2;
- public static final short LOSSLESS = (short) 0xFFC3;
- public static final short DIFFERENTIAL_SEQUENTIAL = (short) 0xFFC5;
- public static final short DIFFERENTIAL_PROGRESSIVE = (short) 0xFFC6;
- public static final short DIFFERENTIAL_LOSSLESS = (short) 0xFFC7;
- public static final short EXTENDED_SEQ_ARITHMETIC_CODING = (short) 0xFFC9;
- public static final short PROGRESSIVE_AIRTHMETIC_CODING = (short) 0xFFCA;
- public static final short LOSSLESS_AITHMETIC_CODING = (short) 0xFFCB;
- public static final short DIFFERENTIAL_SEQ_ARITHMETIC_CODING = (short) 0xFFCD;
- public static final short DIFFERENTIAL_PROGRESSIVE_ARITHMETIC_CODING = (short) 0xFFCE;
- public static final short DIFFERENTIAL_LOSSLESS_ARITHMETIC_CODING = (short) 0xFFCF;
- }
-
+ @SuppressWarnings("unused")
+ public interface JpegProcess {
+ short BASELINE = (short) 0xFFC0;
+ short EXTENDED_SEQUENTIAL = (short) 0xFFC1;
+ short PROGRESSIVE = (short) 0xFFC2;
+ short LOSSLESS = (short) 0xFFC3;
+ short DIFFERENTIAL_SEQUENTIAL = (short) 0xFFC5;
+ short DIFFERENTIAL_PROGRESSIVE = (short) 0xFFC6;
+ short DIFFERENTIAL_LOSSLESS = (short) 0xFFC7;
+ short EXTENDED_SEQ_ARITHMETIC_CODING = (short) 0xFFC9;
+ short PROGRESSIVE_AIRTHMETIC_CODING = (short) 0xFFCA;
+ short LOSSLESS_AITHMETIC_CODING = (short) 0xFFCB;
+ short DIFFERENTIAL_SEQ_ARITHMETIC_CODING = (short) 0xFFCD;
+ short DIFFERENTIAL_PROGRESSIVE_ARITHMETIC_CODING = (short) 0xFFCE;
+ short DIFFERENTIAL_LOSSLESS_ARITHMETIC_CODING = (short) 0xFFCF;
+ }
+
/**
* Constants for the {@link #TAG_SENSITIVITY_TYPE} tag
*/
- @SuppressWarnings( "unused" )
- public static interface SensitivityType {
-
- public static final short UNKNOWN = 0;
-
- /** Standard output sensitivity */
- public static final short SOS = 1;
-
- /** Recommended exposure index */
- public static final short REI = 2;
-
- /** ISO Speed */
- public static final short ISO = 3;
-
- /** Standard output sensitivity and Recommended output index */
- public static final short SOS_REI = 4;
-
- /** Standard output sensitivity and ISO speed */
- public static final short SOS_ISO = 5;
-
- /** Recommended output index and ISO Speed */
- public static final short REI_ISO = 6;
-
- /** Standard output sensitivity and Recommended output index and ISO Speed */
- public static final short SOS_REI_ISO = 7;
+ @SuppressWarnings("unused")
+ public interface SensitivityType {
+
+ short UNKNOWN = 0;
+
+ /**
+ * Standard output sensitivity
+ */
+ short SOS = 1;
+
+ /**
+ * Recommended exposure index
+ */
+ short REI = 2;
+
+ /**
+ * ISO Speed
+ */
+ short ISO = 3;
+
+ /**
+ * Standard output sensitivity and Recommended output index
+ */
+ short SOS_REI = 4;
+
+ /**
+ * Standard output sensitivity and ISO speed
+ */
+ short SOS_ISO = 5;
+
+ /**
+ * Recommended output index and ISO Speed
+ */
+ short REI_ISO = 6;
+
+ /**
+ * Standard output sensitivity and Recommended output index and ISO Speed
+ */
+ short SOS_REI_ISO = 7;
}
-
+
/**
* Options for calling {@link #readExif(java.io.InputStream, int)}, {@link #readExif(byte[], int)},
* {@link #readExif(String, int)}
*/
- public static interface Options {
+ public interface Options {
/**
* Option bit to request to parse IFD0.
*/
@@ -2853,70 +2874,70 @@ public static interface Options {
*/
int OPTION_ALL = OPTION_IFD_0 ^ OPTION_IFD_1 ^ OPTION_IFD_EXIF ^ OPTION_IFD_GPS ^ OPTION_IFD_INTEROPERABILITY ^ OPTION_THUMBNAIL;
}
-
+
public ExifData getExifData(){
return mData;
}
-
- public interface ModifyExifTagCallback{
- boolean modify(ExifInterface ei);
+
+ public interface ModifyExifTagCallback {
+ boolean modify( ExifInterface ei );
}
- public static class ModifyExifTagFailedException extends Exception{
-
+
+ public static class ModifyExifTagFailedException extends Exception {
+
}
-
+
public static void modifyExifTag(
- final InputStream input
- ,final int exif_read_options
- ,final OutputStream output
- ,ModifyExifTagCallback callback
- ) throws IOException,ModifyExifTagFailedException
- {
+ final InputStream input
+ , final int exif_read_options
+ , final OutputStream output
+ , ModifyExifTagCallback callback
+ ) throws IOException, ModifyExifTagFailedException{
ExifInterface src_exif = new ExifInterface();
src_exif.readExif( input, exif_read_options );
- if(! callback.modify(src_exif) ){
+ if( ! callback.modify( src_exif ) ){
throw new ModifyExifTagFailedException();
}
-
+
// 5. write headers
output.write( 0xFF );
output.write( JpegHeader.TAG_SOI );
-
- final List sections = src_exif.mData.getSections();
-
- if( sections.size() > 0 && sections.get( 0 ).type != JpegHeader.TAG_M_JFIF ) {
+
+ final List< ExifParser.Section > sections = src_exif.mData.getSections();
+
+ if( sections.size() > 0 && sections.get( 0 ).type != JpegHeader.TAG_M_JFIF ){
Log.w( TAG, "first section is not a JFIF or EXIF tag" );
output.write( JpegHeader.JFIF_HEADER );
}
-
+
// 6.1 write the *new* EXIF tag
ExifOutputStream eo = new ExifOutputStream( src_exif );
eo.setExifData( src_exif.getExifData() );
eo.writeExifData( output );
-
+
// 6.2 write all the sections except for the SOS ( start of scan )
- for( int a = 0; a < sections.size() - 1; a++ ) {
+ for( int a = 0 ; a < sections.size() - 1 ; a++ ){
ExifParser.Section current = sections.get( a );
// Log.v( TAG, "writing section.. " + String.format( "0x%2X", current.type ) );
output.write( 0xFF );
output.write( current.type );
output.write( current.data );
}
-
+
// 6.3 write the last SOS marker
ExifParser.Section current = sections.get( sections.size() - 1 );
// Log.v( TAG, "writing last section.. " + String.format( "0x%2X", current.type ) );
output.write( 0xFF );
output.write( current.type );
output.write( current.data );
-
- // // the position where the input stream should be copied
- // src_exif.mData.mUncompressedDataPosition;
-
+
+ // // the position where the input stream should be copied
+ // src_exif.mData.mUncompressedDataPosition;
+
// 7. write the rest of the image..
IOUtils.copy( input, output );
-
+
output.flush();
}
-
+
}
diff --git a/gradle.properties b/gradle.properties
index 3530b01..e648c5a 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -9,6 +9,8 @@
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
+android.enableJetifier=true
+android.useAndroidX=true
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 2df53b5..15074d9 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
\ No newline at end of file
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
\ No newline at end of file