summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/java/android/app/IUiAutomationConnection.aidl4
-rw-r--r--core/java/android/app/Notification.java3
-rw-r--r--core/java/android/app/assist/AssistStructure.java71
-rw-r--r--core/java/android/bluetooth/le/BluetoothLeScanner.java8
-rw-r--r--core/java/android/content/ContentProvider.java106
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl2
-rw-r--r--core/java/android/content/pm/PackageManager.java7
-rw-r--r--core/java/android/os/FileUtils.java12
-rw-r--r--core/java/android/os/IDeviceIdleController.aidl1
-rw-r--r--core/java/android/provider/DocumentsProvider.java6
-rw-r--r--core/java/android/provider/Settings.java8
-rw-r--r--core/java/android/text/Hyphenator.java24
-rw-r--r--core/java/android/util/LocalLog.java33
-rw-r--r--core/java/android/view/ViewRootImpl.java5
-rw-r--r--core/java/android/view/inputmethod/InputMethodManagerInternal.java30
-rw-r--r--core/java/android/webkit/WebChromeClient.java8
-rw-r--r--core/java/android/widget/AppSecurityPermissions.java8
-rw-r--r--core/java/android/widget/Editor.java123
-rw-r--r--core/java/android/widget/RelativeLayout.java7
-rw-r--r--core/java/com/android/internal/logging/MetricsLogger.java15
-rw-r--r--core/java/com/android/internal/midi/MidiConstants.java26
-rw-r--r--core/java/com/android/internal/midi/MidiFramer.java31
-rw-r--r--core/java/com/android/internal/os/BatteryStatsHelper.java24
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java32
-rw-r--r--core/java/com/android/internal/widget/LockPatternView.java168
-rw-r--r--core/jni/AndroidRuntime.cpp7
-rwxr-xr-xcore/jni/android/graphics/Bitmap.cpp21
-rw-r--r--core/jni/android_hardware_camera2_DngCreator.cpp1025
-rw-r--r--core/res/AndroidManifest.xml4
-rw-r--r--core/res/res/values-es/strings.xml2
-rw-r--r--core/res/res/values-mcc310-mnc260-pt-rBR/strings.xml32
-rw-r--r--core/res/res/values-mcc425/config.xml21
-rw-r--r--core/res/res/values-mcc432/config.xml21
-rw-r--r--core/res/res/values-mn-rMN/strings.xml2
-rw-r--r--core/res/res/values-pt-rBR-watch/strings.xml24
-rw-r--r--core/res/res/values-sq-rAL/strings.xml2
-rwxr-xr-xcore/res/res/values/config.xml1
-rw-r--r--core/res/res/values/public.xml2
-rw-r--r--core/res/res/values/strings.xml3
-rwxr-xr-xcore/res/res/values/symbols.xml1
40 files changed, 1290 insertions, 640 deletions
diff --git a/core/java/android/app/IUiAutomationConnection.aidl b/core/java/android/app/IUiAutomationConnection.aidl
index 8ab9ac3..474154b 100644
--- a/core/java/android/app/IUiAutomationConnection.aidl
+++ b/core/java/android/app/IUiAutomationConnection.aidl
@@ -38,10 +38,12 @@ interface IUiAutomationConnection {
boolean injectInputEvent(in InputEvent event, boolean sync);
boolean setRotation(int rotation);
Bitmap takeScreenshot(int width, int height);
- void shutdown();
boolean clearWindowContentFrameStats(int windowId);
WindowContentFrameStats getWindowContentFrameStats(int windowId);
void clearWindowAnimationFrameStats();
WindowAnimationFrameStats getWindowAnimationFrameStats();
void executeShellCommand(String command, in ParcelFileDescriptor fd);
+
+ // Called from the system process.
+ oneway void shutdown();
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index b0d8541..fc71783 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1862,6 +1862,9 @@ public class Notification implements Parcelable
} else {
sb.append("null");
}
+ if (this.tickerText != null) {
+ sb.append(" tick");
+ }
sb.append(" defaults=0x");
sb.append(Integer.toHexString(this.defaults));
sb.append(" flags=0x");
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 40126d6..ee0fc91 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -4,6 +4,7 @@ import android.app.Activity;
import android.content.ComponentName;
import android.graphics.Matrix;
import android.graphics.Rect;
+import android.os.BadParcelableException;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
@@ -31,8 +32,12 @@ public class AssistStructure implements Parcelable {
static final String TAG = "AssistStructure";
static final boolean DEBUG_PARCEL = false;
+ static final boolean DEBUG_PARCEL_CHILDREN = false;
static final boolean DEBUG_PARCEL_TREE = false;
+ static final int VALIDATE_WINDOW_TOKEN = 0x11111111;
+ static final int VALIDATE_VIEW_TOKEN = 0x22222222;
+
boolean mHaveData;
ComponentName mActivityComponent;
@@ -173,6 +178,26 @@ public class AssistStructure implements Parcelable {
mCurViewStackEntry = entry;
}
+ void writeView(ViewNode child, Parcel out, PooledStringWriter pwriter, int levelAdj) {
+ if (DEBUG_PARCEL) Log.d(TAG, "write view: at " + out.dataPosition()
+ + ", windows=" + mNumWrittenWindows
+ + ", views=" + mNumWrittenViews
+ + ", level=" + (mCurViewStackPos+levelAdj));
+ out.writeInt(VALIDATE_VIEW_TOKEN);
+ int flags = child.writeSelfToParcel(out, pwriter, mTmpMatrix);
+ mNumWrittenViews++;
+ // If the child has children, push it on the stack to write them next.
+ if ((flags&ViewNode.FLAGS_HAS_CHILDREN) != 0) {
+ if (DEBUG_PARCEL_TREE || DEBUG_PARCEL_CHILDREN) Log.d(TAG,
+ "Preparing to write " + child.mChildren.length
+ + " children: @ #" + mNumWrittenViews
+ + ", level " + (mCurViewStackPos+levelAdj));
+ out.writeInt(child.mChildren.length);
+ int pos = ++mCurViewStackPos;
+ pushViewStackEntry(child, pos);
+ }
+ }
+
boolean writeNextEntryToParcel(AssistStructure as, Parcel out, PooledStringWriter pwriter) {
// Write next view node if appropriate.
if (mCurViewStackEntry != null) {
@@ -182,20 +207,7 @@ public class AssistStructure implements Parcelable {
+ mCurViewStackEntry.curChild + " in " + mCurViewStackEntry.node);
ViewNode child = mCurViewStackEntry.node.mChildren[mCurViewStackEntry.curChild];
mCurViewStackEntry.curChild++;
- if (DEBUG_PARCEL) Log.d(TAG, "write view: at " + out.dataPosition()
- + ", windows=" + mNumWrittenWindows
- + ", views=" + mNumWrittenViews);
- out.writeInt(1);
- int flags = child.writeSelfToParcel(out, pwriter, mTmpMatrix);
- mNumWrittenViews++;
- // If the child has children, push it on the stack to write them next.
- if ((flags&ViewNode.FLAGS_HAS_CHILDREN) != 0) {
- if (DEBUG_PARCEL_TREE) Log.d(TAG, "Preparing to write "
- + child.mChildren.length + " children under " + child);
- out.writeInt(child.mChildren.length);
- int pos = ++mCurViewStackPos;
- pushViewStackEntry(child, pos);
- }
+ writeView(child, out, pwriter, 1);
return true;
}
@@ -223,13 +235,13 @@ public class AssistStructure implements Parcelable {
if (DEBUG_PARCEL) Log.d(TAG, "write window #" + pos + ": at " + out.dataPosition()
+ ", windows=" + mNumWrittenWindows
+ ", views=" + mNumWrittenViews);
- out.writeInt(1);
+ out.writeInt(VALIDATE_WINDOW_TOKEN);
win.writeSelfToParcel(out, pwriter, mTmpMatrix);
mNumWrittenWindows++;
ViewNode root = win.mRoot;
mCurViewStackPos = 0;
- if (DEBUG_PARCEL_TREE) Log.d(TAG, "Pushing initial root view " + root);
- pushViewStackEntry(root, 0);
+ if (DEBUG_PARCEL_TREE) Log.d(TAG, "Writing initial root view " + root);
+ writeView(root, out, pwriter, 0);
return true;
}
@@ -271,11 +283,16 @@ public class AssistStructure implements Parcelable {
+ ", views=" + mNumReadViews);
}
- Parcel readParcel() {
+ Parcel readParcel(int validateToken, int level) {
if (DEBUG_PARCEL) Log.d(TAG, "readParcel: at " + mCurParcel.dataPosition()
+ ", avail=" + mCurParcel.dataAvail() + ", windows=" + mNumReadWindows
- + ", views=" + mNumReadViews);
- if (mCurParcel.readInt() != 0) {
+ + ", views=" + mNumReadViews + ", level=" + level);
+ int token = mCurParcel.readInt();
+ if (token != 0) {
+ if (token != validateToken) {
+ throw new BadParcelableException("Got token " + Integer.toHexString(token)
+ + ", expected token " + Integer.toHexString(validateToken));
+ }
return mCurParcel;
}
// We have run out of partial data, need to read another batch.
@@ -406,7 +423,7 @@ public class AssistStructure implements Parcelable {
}
WindowNode(ParcelTransferReader reader) {
- Parcel in = reader.readParcel();
+ Parcel in = reader.readParcel(VALIDATE_WINDOW_TOKEN, 0);
reader.mNumReadWindows++;
mX = in.readInt();
mY = in.readInt();
@@ -414,7 +431,7 @@ public class AssistStructure implements Parcelable {
mHeight = in.readInt();
mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
mDisplayId = in.readInt();
- mRoot = new ViewNode(reader);
+ mRoot = new ViewNode(reader, 0);
}
void writeSelfToParcel(Parcel out, PooledStringWriter pwriter, float[] tmpMatrix) {
@@ -548,8 +565,8 @@ public class AssistStructure implements Parcelable {
ViewNode() {
}
- ViewNode(ParcelTransferReader reader) {
- final Parcel in = reader.readParcel();
+ ViewNode(ParcelTransferReader reader, int nestingLevel) {
+ final Parcel in = reader.readParcel(VALIDATE_VIEW_TOKEN, nestingLevel);
reader.mNumReadViews++;
final PooledStringReader preader = reader.mStringReader;
mClassName = preader.readString();
@@ -604,9 +621,13 @@ public class AssistStructure implements Parcelable {
}
if ((flags&FLAGS_HAS_CHILDREN) != 0) {
final int NCHILDREN = in.readInt();
+ if (DEBUG_PARCEL_TREE || DEBUG_PARCEL_CHILDREN) Log.d(TAG,
+ "Preparing to read " + NCHILDREN
+ + " children: @ #" + reader.mNumReadViews
+ + ", level " + nestingLevel);
mChildren = new ViewNode[NCHILDREN];
for (int i=0; i<NCHILDREN; i++) {
- mChildren[i] = new ViewNode(reader);
+ mChildren[i] = new ViewNode(reader, nestingLevel + 1);
}
}
}
diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java
index e09ab56..2ba8774 100644
--- a/core/java/android/bluetooth/le/BluetoothLeScanner.java
+++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java
@@ -79,6 +79,10 @@ public final class BluetoothLeScanner {
* delivered through {@code callback}.
* <p>
* Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
+ * An app must hold
+ * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
+ * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
+ * in order to get results.
*
* @param callback Callback used to deliver scan results.
* @throws IllegalArgumentException If {@code callback} is null.
@@ -95,6 +99,10 @@ public final class BluetoothLeScanner {
* Start Bluetooth LE scan. The scan results will be delivered through {@code callback}.
* <p>
* Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
+ * An app must hold
+ * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
+ * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
+ * in order to get results.
*
* @param filters {@link ScanFilter}s for finding exact BLE devices.
* @param settings Settings for the scan.
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 3cc7684..ba9cf7c 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -16,8 +16,11 @@
package android.content;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_ERRORED;
+import static android.app.AppOpsManager.MODE_IGNORED;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -40,8 +43,8 @@ import android.os.OperationCanceledException;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.UserHandle;
-import android.util.Log;
import android.text.TextUtils;
+import android.util.Log;
import java.io.File;
import java.io.FileDescriptor;
@@ -474,14 +477,9 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
private int enforceReadPermission(String callingPkg, Uri uri, IBinder callerToken)
throws SecurityException {
- enforceReadPermissionInner(uri, callerToken);
-
- final int permOp = AppOpsManager.permissionToOpCode(mReadPermission);
- if (permOp != AppOpsManager.OP_NONE) {
- final int mode = mAppOpsManager.noteProxyOp(permOp, callingPkg);
- if (mode != AppOpsManager.MODE_ALLOWED) {
- return mode;
- }
+ final int mode = enforceReadPermissionInner(uri, callingPkg, callerToken);
+ if (mode != MODE_ALLOWED) {
+ return mode;
}
if (mReadOp != AppOpsManager.OP_NONE) {
@@ -493,14 +491,9 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
private int enforceWritePermission(String callingPkg, Uri uri, IBinder callerToken)
throws SecurityException {
- enforceWritePermissionInner(uri, callerToken);
-
- final int permOp = AppOpsManager.permissionToOpCode(mWritePermission);
- if (permOp != AppOpsManager.OP_NONE) {
- final int mode = mAppOpsManager.noteProxyOp(permOp, callingPkg);
- if (mode != AppOpsManager.MODE_ALLOWED) {
- return mode;
- }
+ final int mode = enforceWritePermissionInner(uri, callingPkg, callerToken);
+ if (mode != MODE_ALLOWED) {
+ return mode;
}
if (mWriteOp != AppOpsManager.OP_NONE) {
@@ -518,26 +511,47 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
== PERMISSION_GRANTED;
}
+ /**
+ * Verify that calling app holds both the given permission and any app-op
+ * associated with that permission.
+ */
+ private int checkPermissionAndAppOp(String permission, String callingPkg,
+ IBinder callerToken) {
+ if (getContext().checkPermission(permission, Binder.getCallingPid(), Binder.getCallingUid(),
+ callerToken) != PERMISSION_GRANTED) {
+ return MODE_ERRORED;
+ }
+
+ final int permOp = AppOpsManager.permissionToOpCode(permission);
+ if (permOp != AppOpsManager.OP_NONE) {
+ return mTransport.mAppOpsManager.noteProxyOp(permOp, callingPkg);
+ }
+
+ return MODE_ALLOWED;
+ }
+
/** {@hide} */
- protected void enforceReadPermissionInner(Uri uri, IBinder callerToken)
+ protected int enforceReadPermissionInner(Uri uri, String callingPkg, IBinder callerToken)
throws SecurityException {
final Context context = getContext();
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
String missingPerm = null;
+ int strongestMode = MODE_ALLOWED;
if (UserHandle.isSameApp(uid, mMyUid)) {
- return;
+ return MODE_ALLOWED;
}
if (mExported && checkUser(pid, uid, context)) {
final String componentPerm = getReadPermission();
if (componentPerm != null) {
- if (context.checkPermission(componentPerm, pid, uid, callerToken)
- == PERMISSION_GRANTED) {
- return;
+ final int mode = checkPermissionAndAppOp(componentPerm, callingPkg, callerToken);
+ if (mode == MODE_ALLOWED) {
+ return MODE_ALLOWED;
} else {
missingPerm = componentPerm;
+ strongestMode = Math.max(strongestMode, mode);
}
}
@@ -551,14 +565,15 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
for (PathPermission pp : pps) {
final String pathPerm = pp.getReadPermission();
if (pathPerm != null && pp.match(path)) {
- if (context.checkPermission(pathPerm, pid, uid, callerToken)
- == PERMISSION_GRANTED) {
- return;
+ final int mode = checkPermissionAndAppOp(pathPerm, callingPkg, callerToken);
+ if (mode == MODE_ALLOWED) {
+ return MODE_ALLOWED;
} else {
// any denied <path-permission> means we lose
// default <provider> access.
allowDefaultRead = false;
missingPerm = pathPerm;
+ strongestMode = Math.max(strongestMode, mode);
}
}
}
@@ -566,7 +581,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
// if we passed <path-permission> checks above, and no default
// <provider> permission, then allow access.
- if (allowDefaultRead) return;
+ if (allowDefaultRead) return MODE_ALLOWED;
}
// last chance, check against any uri grants
@@ -575,7 +590,13 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
? maybeAddUserId(uri, callingUserId) : uri;
if (context.checkUriPermission(userUri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION,
callerToken) == PERMISSION_GRANTED) {
- return;
+ return MODE_ALLOWED;
+ }
+
+ // If the worst denial we found above was ignored, then pass that
+ // ignored through; otherwise we assume it should be a real error below.
+ if (strongestMode == MODE_IGNORED) {
+ return MODE_IGNORED;
}
final String failReason = mExported
@@ -587,25 +608,27 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
}
/** {@hide} */
- protected void enforceWritePermissionInner(Uri uri, IBinder callerToken)
+ protected int enforceWritePermissionInner(Uri uri, String callingPkg, IBinder callerToken)
throws SecurityException {
final Context context = getContext();
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
String missingPerm = null;
+ int strongestMode = MODE_ALLOWED;
if (UserHandle.isSameApp(uid, mMyUid)) {
- return;
+ return MODE_ALLOWED;
}
if (mExported && checkUser(pid, uid, context)) {
final String componentPerm = getWritePermission();
if (componentPerm != null) {
- if (context.checkPermission(componentPerm, pid, uid, callerToken)
- == PERMISSION_GRANTED) {
- return;
+ final int mode = checkPermissionAndAppOp(componentPerm, callingPkg, callerToken);
+ if (mode == MODE_ALLOWED) {
+ return MODE_ALLOWED;
} else {
missingPerm = componentPerm;
+ strongestMode = Math.max(strongestMode, mode);
}
}
@@ -619,14 +642,15 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
for (PathPermission pp : pps) {
final String pathPerm = pp.getWritePermission();
if (pathPerm != null && pp.match(path)) {
- if (context.checkPermission(pathPerm, pid, uid, callerToken)
- == PERMISSION_GRANTED) {
- return;
+ final int mode = checkPermissionAndAppOp(pathPerm, callingPkg, callerToken);
+ if (mode == MODE_ALLOWED) {
+ return MODE_ALLOWED;
} else {
// any denied <path-permission> means we lose
// default <provider> access.
allowDefaultWrite = false;
missingPerm = pathPerm;
+ strongestMode = Math.max(strongestMode, mode);
}
}
}
@@ -634,13 +658,19 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
// if we passed <path-permission> checks above, and no default
// <provider> permission, then allow access.
- if (allowDefaultWrite) return;
+ if (allowDefaultWrite) return MODE_ALLOWED;
}
// last chance, check against any uri grants
if (context.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
callerToken) == PERMISSION_GRANTED) {
- return;
+ return MODE_ALLOWED;
+ }
+
+ // If the worst denial we found above was ignored, then pass that
+ // ignored through; otherwise we assume it should be a real error below.
+ if (strongestMode == MODE_IGNORED) {
+ return MODE_IGNORED;
}
final String failReason = mExported
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index ceb610a..bc24d67 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -253,7 +253,7 @@ interface IPackageManager {
List<PackageInfo> getPreferredPackages(int flags);
- void resetPreferredActivities(int userId);
+ void resetApplicationPreferences(int userId);
ResolveInfo getLastChosenActivity(in Intent intent,
String resolvedType, int flags);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 6533bbc..cda5816 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1514,6 +1514,13 @@ public abstract class PackageManager {
/**
* Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device has biometric hardware to detect a fingerprint.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_FINGERPRINT = "android.hardware.fingerprint";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device supports portrait orientation
* screens. For backwards compatibility, you can assume that if neither
* this nor {@link #FEATURE_SCREEN_LANDSCAPE} is set then the device supports
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 864225a..af4c2bc 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -16,6 +16,7 @@
package android.os;
+import android.annotation.NonNull;
import android.provider.DocumentsContract.Document;
import android.system.ErrnoException;
import android.system.Os;
@@ -69,6 +70,8 @@ public class FileUtils {
/** Regular expression for safe filenames: no spaces or metacharacters */
private static final Pattern SAFE_FILENAME_PATTERN = Pattern.compile("[\\w%+,./=_-]+");
+ private static final File[] EMPTY = new File[0];
+
/**
* Set owner and mode of of given {@link File}.
*
@@ -634,4 +637,13 @@ public class FileUtils {
return new File(parent, name + "." + ext);
}
}
+
+ public static @NonNull File[] listFilesOrEmpty(File dir) {
+ File[] res = dir.listFiles();
+ if (res != null) {
+ return res;
+ } else {
+ return EMPTY;
+ }
+ }
}
diff --git a/core/java/android/os/IDeviceIdleController.aidl b/core/java/android/os/IDeviceIdleController.aidl
index b768852..d3eec1e 100644
--- a/core/java/android/os/IDeviceIdleController.aidl
+++ b/core/java/android/os/IDeviceIdleController.aidl
@@ -29,5 +29,6 @@ interface IDeviceIdleController {
boolean isPowerSaveWhitelistApp(String name);
void addPowerSaveTempWhitelistApp(String name, long duration, int userId, String reason);
long addPowerSaveTempWhitelistAppForMms(String name, int userId, String reason);
+ long addPowerSaveTempWhitelistAppForSms(String name, int userId, String reason);
void exitIdle(String reason);
}
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index 6979bee..5a341fc 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -640,7 +640,7 @@ public abstract class DocumentsProvider extends ContentProvider {
final Bundle out = new Bundle();
try {
if (METHOD_CREATE_DOCUMENT.equals(method)) {
- enforceWritePermissionInner(documentUri, null);
+ enforceWritePermissionInner(documentUri, getCallingPackage(), null);
final String mimeType = extras.getString(Document.COLUMN_MIME_TYPE);
final String displayName = extras.getString(Document.COLUMN_DISPLAY_NAME);
@@ -654,7 +654,7 @@ public abstract class DocumentsProvider extends ContentProvider {
out.putParcelable(DocumentsContract.EXTRA_URI, newDocumentUri);
} else if (METHOD_RENAME_DOCUMENT.equals(method)) {
- enforceWritePermissionInner(documentUri, null);
+ enforceWritePermissionInner(documentUri, getCallingPackage(), null);
final String displayName = extras.getString(Document.COLUMN_DISPLAY_NAME);
final String newDocumentId = renameDocument(documentId, displayName);
@@ -678,7 +678,7 @@ public abstract class DocumentsProvider extends ContentProvider {
}
} else if (METHOD_DELETE_DOCUMENT.equals(method)) {
- enforceWritePermissionInner(documentUri, null);
+ enforceWritePermissionInner(documentUri, getCallingPackage(), null);
deleteDocument(documentId);
// Document no longer exists, clean up any grants
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index fff355b..a79970c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7578,14 +7578,6 @@ public final class Settings {
public static final String WFC_IMS_ROAMING_ENABLED = "wfc_ims_roaming_enabled";
/**
- * Global override to disable VoLTE (independent of user setting)
- * <p>
- * Type: int (1 for disable VoLTE, 0 to use user configuration)
- * @hide
- */
- public static final String VOLTE_FEATURE_DISABLED = "volte_feature_disabled";
-
- /**
* Whether user can enable/disable LTE as a preferred network. A carrier might control
* this via gservices, OMA-DM, carrier app, etc.
* <p>
diff --git a/core/java/android/text/Hyphenator.java b/core/java/android/text/Hyphenator.java
index 1ee3827..10a994a 100644
--- a/core/java/android/text/Hyphenator.java
+++ b/core/java/android/text/Hyphenator.java
@@ -45,6 +45,8 @@ public class Hyphenator {
@GuardedBy("sLock")
final static HashMap<Locale, Hyphenator> sMap = new HashMap<Locale, Hyphenator>();
+ final static Hyphenator sEmptyHyphenator = new Hyphenator(StaticLayout.nLoadHyphenator(""));
+
final private long mNativePtr;
private Hyphenator(long nativePtr) {
@@ -53,19 +55,19 @@ public class Hyphenator {
public static long get(@Nullable Locale locale) {
synchronized (sLock) {
- if (sMap.containsKey(locale)) {
- Hyphenator result = sMap.get(locale);
- return (result == null) ? 0 : result.mNativePtr;
+ Hyphenator result = sMap.get(locale);
+ if (result != null) {
+ return result.mNativePtr;
}
// TODO: Convert this a proper locale-fallback system
// Fall back to language-only, if available
Locale languageOnlyLocale = new Locale(locale.getLanguage());
- if (sMap.containsKey(languageOnlyLocale)) {
- Hyphenator result = sMap.get(languageOnlyLocale);
+ result = sMap.get(languageOnlyLocale);
+ if (result != null) {
sMap.put(locale, result);
- return (result == null) ? 0 : result.mNativePtr;
+ return result.mNativePtr;
}
// Fall back to script-only, if available
@@ -75,16 +77,16 @@ public class Hyphenator {
.setLanguage("und")
.setScript(script)
.build();
- if (sMap.containsKey(scriptOnlyLocale)) {
- Hyphenator result = sMap.get(scriptOnlyLocale);
+ result = sMap.get(scriptOnlyLocale);
+ if (result != null) {
sMap.put(locale, result);
- return (result == null) ? 0 : result.mNativePtr;
+ return result.mNativePtr;
}
}
- sMap.put(locale, null); // To remember we found nothing.
+ sMap.put(locale, sEmptyHyphenator); // To remember we found nothing.
}
- return 0;
+ return sEmptyHyphenator.mNativePtr;
}
private static Hyphenator loadHyphenator(String languageTag) {
diff --git a/core/java/android/util/LocalLog.java b/core/java/android/util/LocalLog.java
index 39f66a5..a405dab 100644
--- a/core/java/android/util/LocalLog.java
+++ b/core/java/android/util/LocalLog.java
@@ -30,20 +30,32 @@ public final class LocalLog {
private LinkedList<String> mLog;
private int mMaxLines;
private long mNow;
+ private final boolean mKeepFirst;
public LocalLog(int maxLines) {
mLog = new LinkedList<String>();
mMaxLines = maxLines;
+ mKeepFirst = false;
+ }
+
+ public LocalLog(int maxLines, boolean keepFirst) {
+ mLog = new LinkedList<String>();
+ mMaxLines = maxLines;
+ mKeepFirst = keepFirst;
}
public synchronized void log(String msg) {
+ mNow = System.currentTimeMillis();
+ StringBuilder sb = new StringBuilder();
+ Calendar c = Calendar.getInstance();
+ c.setTimeInMillis(mNow);
+ sb.append(String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c));
+ logStraight(sb.toString() + " - " + msg);
+ }
+
+ private synchronized void logStraight(String msg) {
+ if (mKeepFirst == false || mLog.size() < mMaxLines) mLog.add(msg);
if (mMaxLines > 0) {
- mNow = System.currentTimeMillis();
- StringBuilder sb = new StringBuilder();
- Calendar c = Calendar.getInstance();
- c.setTimeInMillis(mNow);
- sb.append(String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c));
- mLog.add(sb.toString() + " - " + msg);
while (mLog.size() > mMaxLines) mLog.remove();
}
}
@@ -74,4 +86,13 @@ public final class LocalLog {
public ReadOnlyLocalLog readOnlyLocalLog() {
return new ReadOnlyLocalLog(this);
}
+
+ public synchronized void copyTo(LocalLog other, int lines) {
+ int end = mLog.size()-1;
+ int begin = end - lines;
+ if (begin < 0) begin = 0;
+ for (; begin < end; begin++) {
+ other.logStraight(mLog.get(begin));
+ }
+ }
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 9b1db57..c22c0ef 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -555,11 +555,6 @@ public final class ViewRootImpl implements ViewParent,
mPendingContentInsets.set(mAttachInfo.mContentInsets);
mPendingStableInsets.set(mAttachInfo.mStableInsets);
mPendingVisibleInsets.set(0, 0, 0, 0);
- try {
- relayoutWindow(attrs, getHostVisibility(), false);
- } catch (RemoteException e) {
- if (DEBUG_LAYOUT) Log.e(TAG, "failed to relayoutWindow", e);
- }
if (DEBUG_LAYOUT) Log.v(TAG, "Added window " + mWindow);
if (res < WindowManagerGlobal.ADD_OKAY) {
mAttachInfo.mRootView = null;
diff --git a/core/java/android/view/inputmethod/InputMethodManagerInternal.java b/core/java/android/view/inputmethod/InputMethodManagerInternal.java
new file mode 100644
index 0000000..c22127b
--- /dev/null
+++ b/core/java/android/view/inputmethod/InputMethodManagerInternal.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.inputmethod;
+
+/**
+ * Input method manager local system service interface.
+ *
+ * @hide Only for use within the system server.
+ */
+public interface InputMethodManagerInternal {
+ /**
+ * Called by the power manager to tell the input method manager whether it
+ * should start watching for wake events.
+ */
+ public void setInteractive(boolean interactive);
+}
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 0b18bb8..4737e9b 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -284,19 +284,13 @@ public class WebChromeClient {
* currently set for that origin. The host application should invoke the
* specified callback with the desired permission state. See
* {@link GeolocationPermissions} for details.
- *
- * If this method isn't overridden, the callback is invoked with permission
- * denied state.
- *
* @param origin The origin of the web content attempting to use the
* Geolocation API.
* @param callback The callback to use to set the permission state for the
* origin.
*/
public void onGeolocationPermissionsShowPrompt(String origin,
- GeolocationPermissions.Callback callback) {
- callback.invoke(origin, false, false);
- }
+ GeolocationPermissions.Callback callback) {}
/**
* Notify the host application that a request for Geolocation permissions,
diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java
index e3ce6f2..a12b15e 100644
--- a/core/java/android/widget/AppSecurityPermissions.java
+++ b/core/java/android/widget/AppSecurityPermissions.java
@@ -533,6 +533,12 @@ public class AppSecurityPermissions {
int existingReqFlags) {
final int base = pInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
final boolean isNormal = (base == PermissionInfo.PROTECTION_NORMAL);
+
+ // We do not show normal permissions in the UI.
+ if (isNormal) {
+ return false;
+ }
+
final boolean isDangerous = (base == PermissionInfo.PROTECTION_DANGEROUS)
|| ((pInfo.protectionLevel&PermissionInfo.PROTECTION_FLAG_PRE23) != 0);
final boolean isRequired =
@@ -546,7 +552,7 @@ public class AppSecurityPermissions {
// Dangerous and normal permissions are always shown to the user if the permission
// is required, or it was previously granted
- if ((isNormal || isDangerous) && (isRequired || wasGranted || isGranted)) {
+ if (isDangerous && (isRequired || wasGranted || isGranted)) {
return true;
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 15d13ae..010cb27 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -1004,7 +1004,8 @@ public class Editor {
}
if (!handled && mTextActionMode != null) {
- if (touchPositionIsInSelection()) {
+ // TODO: Fix dragging in extracted mode.
+ if (touchPositionIsInSelection() && !mTextView.isInExtractedMode()) {
// Start a drag
final int start = mTextView.getSelectionStart();
final int end = mTextView.getSelectionEnd();
@@ -4059,9 +4060,17 @@ public class Editor {
private float mPrevX;
// Indicates if the handle has moved a boundary between LTR and RTL text.
private boolean mLanguageDirectionChanged = false;
+ // Distance from edge of horizontally scrolling text view
+ // to use to switch to character mode.
+ private final float mTextViewEdgeSlop;
+ // Used to save text view location.
+ private final int[] mTextViewLocation = new int[2];
public SelectionStartHandleView(Drawable drawableLtr, Drawable drawableRtl) {
super(drawableLtr, drawableRtl);
+ ViewConfiguration viewConfiguration = ViewConfiguration.get(
+ mTextView.getContext());
+ mTextViewEdgeSlop = viewConfiguration.getScaledTouchSlop() * 4;
}
@Override
@@ -4099,7 +4108,7 @@ public class Editor {
if (layout == null) {
// HandleView will deal appropriately in positionAtCursorOffset when
// layout is null.
- positionAtCursorOffset(mTextView.getOffsetForPosition(x, y), false);
+ positionAndAdjustForCrossingHandles(mTextView.getOffsetForPosition(x, y));
return;
}
@@ -4141,12 +4150,12 @@ public class Editor {
// to the current position.
mLanguageDirectionChanged = true;
mTouchWordDelta = 0.0f;
- positionAtCursorOffset(offset, false);
+ positionAndAdjustForCrossingHandles(offset);
return;
} else if (mLanguageDirectionChanged && !isLvlBoundary) {
// We've just moved past the boundary so update the position. After this we can
// figure out if the user is expanding or shrinking to go by word or character.
- positionAtCursorOffset(offset, false);
+ positionAndAdjustForCrossingHandles(offset);
mTouchWordDelta = 0.0f;
mLanguageDirectionChanged = false;
return;
@@ -4159,6 +4168,21 @@ public class Editor {
}
}
+ if (mTextView.getHorizontallyScrolling()) {
+ if (positionNearEdgeOfScrollingView(x, atRtl)
+ && (mTextView.getScrollX() != 0)
+ && ((isExpanding && offset < selectionStart) || !isExpanding)) {
+ // If we're expanding ensure that the offset is smaller than the
+ // selection start, if the handle snapped to the word, the finger position
+ // may be out of sync and we don't want the selection to jump back.
+ mTouchWordDelta = 0.0f;
+ final int nextOffset = atRtl ? layout.getOffsetToRightOf(mPreviousOffset)
+ : layout.getOffsetToLeftOf(mPreviousOffset);
+ positionAndAdjustForCrossingHandles(nextOffset);
+ return;
+ }
+ }
+
if (isExpanding) {
// User is increasing the selection.
if (!mInWord || currLine < mPrevLine) {
@@ -4214,17 +4238,22 @@ public class Editor {
}
if (positionCursor) {
- // Handles can not cross and selection is at least one character.
- if (offset >= selectionEnd) {
- offset = getNextCursorOffset(selectionEnd, false);
- mTouchWordDelta = 0.0f;
- }
mPreviousLineTouched = currLine;
- positionAtCursorOffset(offset, false);
+ positionAndAdjustForCrossingHandles(offset);
}
mPrevX = x;
}
+ private void positionAndAdjustForCrossingHandles(int offset) {
+ final int selectionEnd = mTextView.getSelectionEnd();
+ if (offset >= selectionEnd) {
+ // Handles can not cross and selection is at least one character.
+ offset = getNextCursorOffset(selectionEnd, false);
+ mTouchWordDelta = 0.0f;
+ }
+ positionAtCursorOffset(offset, false);
+ }
+
@Override
protected void positionAtCursorOffset(int offset, boolean parentScrolled) {
super.positionAtCursorOffset(offset, parentScrolled);
@@ -4242,6 +4271,20 @@ public class Editor {
}
return superResult;
}
+
+ private boolean positionNearEdgeOfScrollingView(float x, boolean atRtl) {
+ mTextView.getLocationOnScreen(mTextViewLocation);
+ boolean nearEdge;
+ if (atRtl) {
+ int rightEdge = mTextViewLocation[0] + mTextView.getWidth()
+ - mTextView.getPaddingRight();
+ nearEdge = x > rightEdge - mTextViewEdgeSlop;
+ } else {
+ int leftEdge = mTextViewLocation[0] + mTextView.getPaddingLeft();
+ nearEdge = x < leftEdge + mTextViewEdgeSlop;
+ }
+ return nearEdge;
+ }
}
private class SelectionEndHandleView extends HandleView {
@@ -4253,9 +4296,17 @@ public class Editor {
private float mPrevX;
// Indicates if the handle has moved a boundary between LTR and RTL text.
private boolean mLanguageDirectionChanged = false;
+ // Distance from edge of horizontally scrolling text view
+ // to use to switch to character mode.
+ private final float mTextViewEdgeSlop;
+ // Used to save the text view location.
+ private final int[] mTextViewLocation = new int[2];
public SelectionEndHandleView(Drawable drawableLtr, Drawable drawableRtl) {
super(drawableLtr, drawableRtl);
+ ViewConfiguration viewConfiguration = ViewConfiguration.get(
+ mTextView.getContext());
+ mTextViewEdgeSlop = viewConfiguration.getScaledTouchSlop() * 4;
}
@Override
@@ -4293,7 +4344,7 @@ public class Editor {
if (layout == null) {
// HandleView will deal appropriately in positionAtCursorOffset when
// layout is null.
- positionAtCursorOffset(mTextView.getOffsetForPosition(x, y), false);
+ positionAndAdjustForCrossingHandles(mTextView.getOffsetForPosition(x, y));
return;
}
@@ -4335,12 +4386,12 @@ public class Editor {
// to the current position.
mLanguageDirectionChanged = true;
mTouchWordDelta = 0.0f;
- positionAtCursorOffset(offset, false);
+ positionAndAdjustForCrossingHandles(offset);
return;
} else if (mLanguageDirectionChanged && !isLvlBoundary) {
// We've just moved past the boundary so update the position. After this we can
// figure out if the user is expanding or shrinking to go by word or character.
- positionAtCursorOffset(offset, false);
+ positionAndAdjustForCrossingHandles(offset);
mTouchWordDelta = 0.0f;
mLanguageDirectionChanged = false;
return;
@@ -4353,6 +4404,21 @@ public class Editor {
}
}
+ if (mTextView.getHorizontallyScrolling()) {
+ if (positionNearEdgeOfScrollingView(x, atRtl)
+ && mTextView.canScrollHorizontally(atRtl ? -1 : 1)
+ && ((isExpanding && offset > selectionEnd) || !isExpanding)) {
+ // If we're expanding ensure that the offset is actually greater than the
+ // selection end, if the handle snapped to the word, the finger position
+ // may be out of sync and we don't want the selection to jump back.
+ mTouchWordDelta = 0.0f;
+ final int nextOffset = atRtl ? layout.getOffsetToLeftOf(mPreviousOffset)
+ : layout.getOffsetToRightOf(mPreviousOffset);
+ positionAndAdjustForCrossingHandles(nextOffset);
+ return;
+ }
+ }
+
if (isExpanding) {
// User is increasing the selection.
if (!mInWord || currLine > mPrevLine) {
@@ -4408,17 +4474,22 @@ public class Editor {
}
if (positionCursor) {
- // Handles can not cross and selection is at least one character.
- if (offset <= selectionStart) {
- offset = getNextCursorOffset(selectionStart, true);
- mTouchWordDelta = 0.0f;
- }
mPreviousLineTouched = currLine;
- positionAtCursorOffset(offset, false);
+ positionAndAdjustForCrossingHandles(offset);
}
mPrevX = x;
}
+ private void positionAndAdjustForCrossingHandles(int offset) {
+ final int selectionStart = mTextView.getSelectionStart();
+ if (offset <= selectionStart) {
+ // Handles can not cross and selection is at least one character.
+ offset = getNextCursorOffset(selectionStart, true);
+ mTouchWordDelta = 0.0f;
+ }
+ positionAtCursorOffset(offset, false);
+ }
+
@Override
protected void positionAtCursorOffset(int offset, boolean parentScrolled) {
super.positionAtCursorOffset(offset, parentScrolled);
@@ -4436,6 +4507,20 @@ public class Editor {
}
return superResult;
}
+
+ private boolean positionNearEdgeOfScrollingView(float x, boolean atRtl) {
+ mTextView.getLocationOnScreen(mTextViewLocation);
+ boolean nearEdge;
+ if (atRtl) {
+ int leftEdge = mTextViewLocation[0] + mTextView.getPaddingLeft();
+ nearEdge = x < leftEdge + mTextViewEdgeSlop;
+ } else {
+ int rightEdge = mTextViewLocation[0] + mTextView.getWidth()
+ - mTextView.getPaddingRight();
+ nearEdge = x > rightEdge - mTextViewEdgeSlop;
+ }
+ return nearEdge;
+ }
}
private int getCurrentLineAdjustedForSlop(Layout layout, int prevLine, float y) {
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index dac02fa..6a561e6 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -731,7 +731,8 @@ public class RelativeLayout extends ViewGroup {
// Negative values in a mySize value in RelativeLayout
// measurement is code for, "we got an unspecified mode in the
// RelativeLayout's measure spec."
- if (mySize < 0 && !mAllowBrokenMeasureSpecs) {
+ final boolean isUnspecified = mySize < 0;
+ if (isUnspecified && !mAllowBrokenMeasureSpecs) {
if (childStart != VALUE_NOT_SET && childEnd != VALUE_NOT_SET) {
// Constraints fixed both edges, so child has an exact size.
childSpecSize = Math.max(0, childEnd - childStart);
@@ -767,7 +768,7 @@ public class RelativeLayout extends ViewGroup {
if (childStart != VALUE_NOT_SET && childEnd != VALUE_NOT_SET) {
// Constraints fixed both edges, so child must be an exact size.
- childSpecMode = MeasureSpec.EXACTLY;
+ childSpecMode = isUnspecified ? MeasureSpec.UNSPECIFIED : MeasureSpec.EXACTLY;
childSpecSize = Math.max(0, maxAvailable);
} else {
if (childSize >= 0) {
@@ -784,7 +785,7 @@ public class RelativeLayout extends ViewGroup {
} else if (childSize == LayoutParams.MATCH_PARENT) {
// Child wanted to be as big as possible. Give all available
// space.
- childSpecMode = MeasureSpec.EXACTLY;
+ childSpecMode = isUnspecified ? MeasureSpec.UNSPECIFIED : MeasureSpec.EXACTLY;
childSpecSize = Math.max(0, maxAvailable);
} else if (childSize == LayoutParams.WRAP_CONTENT) {
// Child wants to wrap content. Use AT_MOST to communicate
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index cbe535f..91ae27b 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -27,7 +27,20 @@ import android.view.View;
*/
public class MetricsLogger implements MetricsConstants {
// Temporary constants go here, to await migration to MetricsConstants.
- // next value is 227;
+ // next value is 238;
+
+ public static final int TUNER = 227;
+ public static final int TUNER_QS = 228;
+ public static final int TUNER_DEMO_MODE = 229;
+
+ public static final int TUNER_QS_REORDER = 230;
+ public static final int TUNER_QS_ADD = 231;
+ public static final int TUNER_QS_REMOVE = 232;
+ public static final int TUNER_STATUS_BAR_ENABLE = 233;
+ public static final int TUNER_STATUS_BAR_DISABLE = 234;
+ public static final int TUNER_DEMO_MODE_ENABLED = 235;
+ public static final int TUNER_DEMO_MODE_ON = 236;
+ public static final int TUNER_BATTERY_PERCENTAGE = 237;
public static void visible(Context context, int category) throws IllegalArgumentException {
if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
diff --git a/core/java/com/android/internal/midi/MidiConstants.java b/core/java/com/android/internal/midi/MidiConstants.java
index c13e5fc..b6b8bf0 100644
--- a/core/java/com/android/internal/midi/MidiConstants.java
+++ b/core/java/com/android/internal/midi/MidiConstants.java
@@ -55,18 +55,30 @@ public final class MidiConstants {
public final static int SYSTEM_BYTE_LENGTHS[] = { 1, 2, 3, 2, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1 };
- /********************************************************************/
- public static int getBytesPerMessage(int command) {
- if ((command < 0x80) || (command > 0xFF)) {
- return 0;
- } else if (command >= 0xF0) {
- return SYSTEM_BYTE_LENGTHS[command & 0x0F];
+ /**
+ * MIDI messages, except for SysEx, are 1,2 or 3 bytes long.
+ * You can tell how long a MIDI message is from the first status byte.
+ * Do not call this for SysEx, which has variable length.
+ * @param statusByte
+ * @return number of bytes in a complete message or zero if data byte passed
+ */
+ public static int getBytesPerMessage(byte statusByte) {
+ // Java bytes are signed so we need to mask off the high bits
+ // to get a value between 0 and 255.
+ int statusInt = statusByte & 0xFF;
+ if (statusInt >= 0xF0) {
+ // System messages use low nibble for size.
+ return SYSTEM_BYTE_LENGTHS[statusInt & 0x0F];
+ } else if(statusInt >= 0x80) {
+ // Channel voice messages use high nibble for size.
+ return CHANNEL_BYTE_LENGTHS[(statusInt >> 4) - 8];
} else {
- return CHANNEL_BYTE_LENGTHS[(command >> 4) - 8];
+ return 0; // data byte
}
}
+
/**
* @param msg
* @param offset
diff --git a/core/java/com/android/internal/midi/MidiFramer.java b/core/java/com/android/internal/midi/MidiFramer.java
index 058f57c..62517fa 100644
--- a/core/java/com/android/internal/midi/MidiFramer.java
+++ b/core/java/com/android/internal/midi/MidiFramer.java
@@ -17,7 +17,7 @@
package com.android.internal.midi;
import android.media.midi.MidiReceiver;
-import android.util.Log;
+//import android.util.Log;
import java.io.IOException;
@@ -37,7 +37,7 @@ public class MidiFramer extends MidiReceiver {
private MidiReceiver mReceiver;
private byte[] mBuffer = new byte[3];
private int mCount;
- private int mRunningStatus;
+ private byte mRunningStatus;
private int mNeeded;
private boolean mInSysEx;
@@ -59,22 +59,22 @@ public class MidiFramer extends MidiReceiver {
@Override
public void onSend(byte[] data, int offset, int count, long timestamp)
throws IOException {
- // Log.i(TAG, formatMidiData(data, offset, count));
int sysExStartOffset = (mInSysEx ? offset : -1);
for (int i = 0; i < count; i++) {
- int b = data[offset] & 0xFF;
- if (b >= 0x80) { // status byte?
- if (b < 0xF0) { // channel message?
- mRunningStatus = (byte) b;
+ final byte currentByte = data[offset];
+ final int currentInt = currentByte & 0xFF;
+ if (currentInt >= 0x80) { // status byte?
+ if (currentInt < 0xF0) { // channel message?
+ mRunningStatus = currentByte;
mCount = 1;
- mNeeded = MidiConstants.getBytesPerMessage(b) - 1;
- } else if (b < 0xF8) { // system common?
- if (b == 0xF0 /* SysEx Start */) {
+ mNeeded = MidiConstants.getBytesPerMessage(currentByte) - 1;
+ } else if (currentInt < 0xF8) { // system common?
+ if (currentInt == 0xF0 /* SysEx Start */) {
// Log.i(TAG, "SysEx Start");
mInSysEx = true;
sysExStartOffset = offset;
- } else if (b == 0xF7 /* SysEx End */) {
+ } else if (currentInt == 0xF7 /* SysEx End */) {
// Log.i(TAG, "SysEx End");
if (mInSysEx) {
mReceiver.send(data, sysExStartOffset,
@@ -83,10 +83,10 @@ public class MidiFramer extends MidiReceiver {
sysExStartOffset = -1;
}
} else {
- mBuffer[0] = (byte) b;
+ mBuffer[0] = currentByte;
mRunningStatus = 0;
mCount = 1;
- mNeeded = MidiConstants.getBytesPerMessage(b) - 1;
+ mNeeded = MidiConstants.getBytesPerMessage(currentByte) - 1;
}
} else { // real-time?
// Single byte message interleaved with other data.
@@ -98,12 +98,11 @@ public class MidiFramer extends MidiReceiver {
mReceiver.send(data, offset, 1, timestamp);
}
} else { // data byte
- // Save SysEx data for SysEx End marker or end of buffer.
if (!mInSysEx) {
- mBuffer[mCount++] = (byte) b;
+ mBuffer[mCount++] = currentByte;
if (--mNeeded == 0) {
if (mRunningStatus != 0) {
- mBuffer[0] = (byte) mRunningStatus;
+ mBuffer[0] = mRunningStatus;
}
mReceiver.send(mBuffer, 0, mCount, timestamp);
mNeeded = MidiConstants.getBytesPerMessage(mBuffer[0]) - 1;
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index 264b8c1..9caf78a 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -47,6 +47,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
+import java.util.Locale;
/**
* A helper class for retrieving the power usage information for all applications and services.
@@ -267,15 +268,20 @@ public final class BatteryStatsHelper {
public static String makemAh(double power) {
if (power == 0) return "0";
- else if (power < .00001) return String.format("%.8f", power);
- else if (power < .0001) return String.format("%.7f", power);
- else if (power < .001) return String.format("%.6f", power);
- else if (power < .01) return String.format("%.5f", power);
- else if (power < .1) return String.format("%.4f", power);
- else if (power < 1) return String.format("%.3f", power);
- else if (power < 10) return String.format("%.2f", power);
- else if (power < 100) return String.format("%.1f", power);
- else return String.format("%.0f", power);
+
+ final String format;
+ if (power < .00001) format = "%.8f";
+ else if (power < .0001) format = "%.7f";
+ else if (power < .001) format = "%.6f";
+ else if (power < .01) format = "%.5f";
+ else if (power < .1) format = "%.4f";
+ else if (power < 1) format = "%.3f";
+ else if (power < 10) format = "%.2f";
+ else if (power < 100) format = "%.1f";
+ else format = "%.0f";
+
+ // Use English locale because this is never used in UI (only in checkin and dump).
+ return String.format(Locale.ENGLISH, format, power);
}
/**
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 60f47d6..e7c58f4 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -2560,14 +2560,24 @@ public final class BatteryStatsImpl extends BatteryStats {
addHistoryEventLocked(elapsedRealtime, uptime, code, name, uid);
}
+ boolean ensureStartClockTime(final long currentTime) {
+ final long ABOUT_ONE_YEAR = 365*24*60*60*1000L;
+ if (currentTime > ABOUT_ONE_YEAR && mStartClockTime < (currentTime-ABOUT_ONE_YEAR)) {
+ // If the start clock time has changed by more than a year, then presumably
+ // the previous time was completely bogus. So we are going to figure out a
+ // new time based on how much time has elapsed since we started counting.
+ mStartClockTime = currentTime - (SystemClock.elapsedRealtime()-(mRealtimeStart/1000));
+ return true;
+ }
+ return false;
+ }
+
public void noteCurrentTimeChangedLocked() {
final long currentTime = System.currentTimeMillis();
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
recordCurrentTimeChangeLocked(currentTime, elapsedRealtime, uptime);
- if (isStartClockTimeValid()) {
- mStartClockTime = currentTime;
- }
+ ensureStartClockTime(currentTime);
}
public void noteProcessStartLocked(String name, int uid) {
@@ -4306,19 +4316,11 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
- boolean isStartClockTimeValid() {
- return mStartClockTime > 365*24*60*60*1000L;
- }
-
@Override public long getStartClockTime() {
- if (!isStartClockTimeValid()) {
- // If the last clock time we got was very small, then we hadn't had a real
- // time yet, so try to get it again.
- mStartClockTime = System.currentTimeMillis();
- if (isStartClockTimeValid()) {
- recordCurrentTimeChangeLocked(mStartClockTime, SystemClock.elapsedRealtime(),
- SystemClock.uptimeMillis());
- }
+ final long currentTime = System.currentTimeMillis();
+ if (ensureStartClockTime(currentTime)) {
+ recordCurrentTimeChangeLocked(currentTime, SystemClock.elapsedRealtime(),
+ SystemClock.uptimeMillis());
}
return mStartClockTime;
}
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 444f878..a709bb8 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -23,10 +23,10 @@ import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
+import android.graphics.CanvasProperty;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
-import android.graphics.RectF;
import android.media.AudioManager;
import android.os.Bundle;
import android.os.Debug;
@@ -38,8 +38,10 @@ import android.provider.Settings;
import android.util.AttributeSet;
import android.util.IntArray;
import android.util.Log;
+import android.view.DisplayListCanvas;
import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
+import android.view.RenderNodeAnimator;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -200,10 +202,16 @@ public class LockPatternView extends View {
}
public static class CellState {
- public float scale = 1.0f;
- public float translateY = 0.0f;
- public float alpha = 1.0f;
- public float size;
+ int row;
+ int col;
+ boolean hwAnimating;
+ CanvasProperty<Float> hwRadius;
+ CanvasProperty<Float> hwCenterX;
+ CanvasProperty<Float> hwCenterY;
+ CanvasProperty<Paint> hwPaint;
+ float radius;
+ float translationY;
+ float alpha = 1f;
public float lineEndX = Float.MIN_VALUE;
public float lineEndY = Float.MIN_VALUE;
public ValueAnimator lineAnimator;
@@ -313,7 +321,9 @@ public class LockPatternView extends View {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
mCellStates[i][j] = new CellState();
- mCellStates[i][j].size = mDotSize;
+ mCellStates[i][j].radius = mDotSize/2;
+ mCellStates[i][j].row = i;
+ mCellStates[i][j].col = j;
}
}
@@ -412,6 +422,112 @@ public class LockPatternView extends View {
invalidate();
}
+ public void startCellStateAnimation(CellState cellState, float startAlpha, float endAlpha,
+ float startTranslationY, float endTranslationY, float startScale, float endScale,
+ long delay, long duration,
+ Interpolator interpolator, Runnable finishRunnable) {
+ if (isHardwareAccelerated()) {
+ startCellStateAnimationHw(cellState, startAlpha, endAlpha, startTranslationY,
+ endTranslationY, startScale, endScale, delay, duration, interpolator,
+ finishRunnable);
+ } else {
+ startCellStateAnimationSw(cellState, startAlpha, endAlpha, startTranslationY,
+ endTranslationY, startScale, endScale, delay, duration, interpolator,
+ finishRunnable);
+ }
+ }
+
+ private void startCellStateAnimationSw(final CellState cellState,
+ final float startAlpha, final float endAlpha,
+ final float startTranslationY, final float endTranslationY,
+ final float startScale, final float endScale,
+ long delay, long duration, Interpolator interpolator, final Runnable finishRunnable) {
+ cellState.alpha = startAlpha;
+ cellState.translationY = startTranslationY;
+ cellState.radius = mDotSize/2 * startScale;
+ ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
+ animator.setDuration(duration);
+ animator.setStartDelay(delay);
+ animator.setInterpolator(interpolator);
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ float t = (float) animation.getAnimatedValue();
+ cellState.alpha = (1 - t) * startAlpha + t * endAlpha;
+ cellState.translationY = (1 - t) * startTranslationY + t * endTranslationY;
+ cellState.radius = mDotSize/2 * ((1 - t) * startScale + t * endScale);
+ invalidate();
+ }
+ });
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (finishRunnable != null) {
+ finishRunnable.run();
+ }
+ }
+ });
+ animator.start();
+ }
+
+ private void startCellStateAnimationHw(final CellState cellState,
+ float startAlpha, float endAlpha,
+ float startTranslationY, float endTranslationY,
+ float startScale, float endScale,
+ long delay, long duration, Interpolator interpolator, final Runnable finishRunnable) {
+ cellState.alpha = endAlpha;
+ cellState.translationY = endTranslationY;
+ cellState.radius = mDotSize/2 * endScale;
+ cellState.hwAnimating = true;
+ cellState.hwCenterY = CanvasProperty.createFloat(
+ getCenterYForRow(cellState.row) + startTranslationY);
+ cellState.hwCenterX = CanvasProperty.createFloat(getCenterXForColumn(cellState.col));
+ cellState.hwRadius = CanvasProperty.createFloat(mDotSize/2 * startScale);
+ mPaint.setColor(getCurrentColor(false));
+ mPaint.setAlpha((int) (startAlpha * 255));
+ cellState.hwPaint = CanvasProperty.createPaint(new Paint(mPaint));
+
+ startRtFloatAnimation(cellState.hwCenterY,
+ getCenterYForRow(cellState.row) + endTranslationY, delay, duration, interpolator);
+ startRtFloatAnimation(cellState.hwRadius, mDotSize/2 * endScale, delay, duration,
+ interpolator);
+ startRtAlphaAnimation(cellState, endAlpha, delay, duration, interpolator,
+ new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ cellState.hwAnimating = false;
+ if (finishRunnable != null) {
+ finishRunnable.run();
+ }
+ }
+ });
+
+ invalidate();
+ }
+
+ private void startRtAlphaAnimation(CellState cellState, float endAlpha,
+ long delay, long duration, Interpolator interpolator,
+ Animator.AnimatorListener listener) {
+ RenderNodeAnimator animator = new RenderNodeAnimator(cellState.hwPaint,
+ RenderNodeAnimator.PAINT_ALPHA, (int) (endAlpha * 255));
+ animator.setDuration(duration);
+ animator.setStartDelay(delay);
+ animator.setInterpolator(interpolator);
+ animator.setTarget(this);
+ animator.addListener(listener);
+ animator.start();
+ }
+
+ private void startRtFloatAnimation(CanvasProperty<Float> property, float endValue,
+ long delay, long duration, Interpolator interpolator) {
+ RenderNodeAnimator animator = new RenderNodeAnimator(property, endValue);
+ animator.setDuration(duration);
+ animator.setStartDelay(delay);
+ animator.setInterpolator(interpolator);
+ animator.setTarget(this);
+ animator.start();
+ }
+
private void notifyCellAdded() {
// sendAccessEvent(R.string.lockscreen_access_pattern_cell_added);
if (mOnPatternListener != null) {
@@ -603,14 +719,15 @@ public class LockPatternView extends View {
private void startCellActivatedAnimation(Cell cell) {
final CellState cellState = mCellStates[cell.row][cell.column];
- startSizeAnimation(mDotSize, mDotSizeActivated, 96, mLinearOutSlowInInterpolator,
+ startRadiusAnimation(mDotSize/2, mDotSizeActivated/2, 96, mLinearOutSlowInInterpolator,
cellState, new Runnable() {
- @Override
- public void run() {
- startSizeAnimation(mDotSizeActivated, mDotSize, 192, mFastOutSlowInInterpolator,
- cellState, null);
- }
- });
+ @Override
+ public void run() {
+ startRadiusAnimation(mDotSizeActivated/2, mDotSize/2, 192,
+ mFastOutSlowInInterpolator,
+ cellState, null);
+ }
+ });
startLineEndAnimation(cellState, mInProgressX, mInProgressY,
getCenterXForColumn(cell.column), getCenterYForRow(cell.row));
}
@@ -639,13 +756,13 @@ public class LockPatternView extends View {
state.lineAnimator = valueAnimator;
}
- private void startSizeAnimation(float start, float end, long duration, Interpolator interpolator,
- final CellState state, final Runnable endRunnable) {
+ private void startRadiusAnimation(float start, float end, long duration,
+ Interpolator interpolator, final CellState state, final Runnable endRunnable) {
ValueAnimator valueAnimator = ValueAnimator.ofFloat(start, end);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
- state.size = (float) animation.getAnimatedValue();
+ state.radius = (float) animation.getAnimatedValue();
invalidate();
}
});
@@ -969,10 +1086,16 @@ public class LockPatternView extends View {
for (int j = 0; j < 3; j++) {
CellState cellState = mCellStates[i][j];
float centerX = getCenterXForColumn(j);
- float size = cellState.size * cellState.scale;
- float translationY = cellState.translateY;
- drawCircle(canvas, (int) centerX, (int) centerY + translationY,
- size, drawLookup[i][j], cellState.alpha);
+ float translationY = cellState.translationY;
+ if (isHardwareAccelerated() && cellState.hwAnimating) {
+ DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas;
+ displayListCanvas.drawCircle(cellState.hwCenterX, cellState.hwCenterY,
+ cellState.hwRadius, cellState.hwPaint);
+ } else {
+ drawCircle(canvas, (int) centerX, (int) centerY + translationY,
+ cellState.radius, drawLookup[i][j], cellState.alpha);
+
+ }
}
}
@@ -1055,11 +1178,11 @@ public class LockPatternView extends View {
/**
* @param partOfPattern Whether this circle is part of the pattern.
*/
- private void drawCircle(Canvas canvas, float centerX, float centerY, float size,
+ private void drawCircle(Canvas canvas, float centerX, float centerY, float radius,
boolean partOfPattern, float alpha) {
mPaint.setColor(getCurrentColor(partOfPattern));
mPaint.setAlpha((int) (alpha * 255));
- canvas.drawCircle(centerX, centerY, size/2, mPaint);
+ canvas.drawCircle(centerX, centerY, radius, mPaint);
}
@Override
@@ -1290,7 +1413,6 @@ public class LockPatternView extends View {
float centerY = getCenterYForRow(row);
float cellheight = mSquareHeight * mHitFactor * 0.5f;
float cellwidth = mSquareWidth * mHitFactor * 0.5f;
- float translationY = cell.translateY;
bounds.left = (int) (centerX - cellwidth);
bounds.right = (int) (centerX + cellwidth);
bounds.top = (int) (centerY - cellheight);
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index bffbab7..bae2cde 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -590,6 +590,7 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
char cpuAbiListBuf[sizeof("--cpu-abilist=") + PROPERTY_VALUE_MAX];
char methodTraceFileBuf[sizeof("-Xmethod-trace-file:") + PROPERTY_VALUE_MAX];
char methodTraceFileSizeBuf[sizeof("-Xmethod-trace-file-size:") + PROPERTY_VALUE_MAX];
+ char fingerprintBuf[sizeof("-Xfingerprint:") + PROPERTY_VALUE_MAX];
bool checkJni = false;
property_get("dalvik.vm.checkjni", propBuf, "");
@@ -908,6 +909,12 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
addOption("--generate-debug-info");
}
+ /*
+ * Retrieve the build fingerprint and provide it to the runtime. That way, ANR dumps will
+ * contain the fingerprint and can be parsed.
+ */
+ parseRuntimeOption("ro.build.fingerprint", fingerprintBuf, "-Xfingerprint:");
+
initArgs.version = JNI_VERSION_1_4;
initArgs.options = mOptions.editArray();
initArgs.nOptions = mOptions.size();
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 0d80a7f..670d3c0 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -475,6 +475,14 @@ static void FromColor_D4444_Raw(void* dst, const SkColor src[], int width,
}
}
+static void FromColor_DA8(void* dst, const SkColor src[], int width, int x, int y) {
+ uint8_t* d = (uint8_t*)dst;
+
+ for (int stop = x + width; x < stop; x++) {
+ *d++ = SkColorGetA(*src++);
+ }
+}
+
// can return NULL
static FromColorProc ChooseFromColorProc(const SkBitmap& bitmap) {
switch (bitmap.colorType()) {
@@ -485,6 +493,8 @@ static FromColorProc ChooseFromColorProc(const SkBitmap& bitmap) {
FromColor_D4444_Raw;
case kRGB_565_SkColorType:
return FromColor_D565;
+ case kAlpha_8_SkColorType:
+ return FromColor_DA8;
default:
break;
}
@@ -632,6 +642,15 @@ static void ToColor_SI8_Opaque(SkColor dst[], const void* src, int width,
} while (--width != 0);
}
+static void ToColor_SA8(SkColor dst[], const void* src, int width, SkColorTable*) {
+ SkASSERT(width > 0);
+ const uint8_t* s = (const uint8_t*)src;
+ do {
+ uint8_t c = *s++;
+ *dst++ = SkColorSetARGB(c, c, c, c);
+ } while (--width != 0);
+}
+
// can return NULL
static ToColorProc ChooseToColorProc(const SkBitmap& src) {
switch (src.colorType()) {
@@ -673,6 +692,8 @@ static ToColorProc ChooseToColorProc(const SkBitmap& src) {
default:
return NULL;
}
+ case kAlpha_8_SkColorType:
+ return ToColor_SA8;
default:
break;
}
diff --git a/core/jni/android_hardware_camera2_DngCreator.cpp b/core/jni/android_hardware_camera2_DngCreator.cpp
index 995d39f..ba08237 100644
--- a/core/jni/android_hardware_camera2_DngCreator.cpp
+++ b/core/jni/android_hardware_camera2_DngCreator.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-//#define LOG_NDEBUG 0
+#define LOG_NDEBUG 0
#define LOG_TAG "DngCreator_JNI"
#include <inttypes.h>
#include <string.h>
@@ -26,6 +26,7 @@
#include <utils/StrongPointer.h>
#include <utils/RefBase.h>
#include <utils/Vector.h>
+#include <utils/String8.h>
#include <cutils/properties.h>
#include <system/camera_metadata.h>
#include <camera/CameraMetadata.h>
@@ -48,13 +49,22 @@
using namespace android;
using namespace img_utils;
-#define BAIL_IF_INVALID(expr, jnienv, tagId, writer) \
+#define BAIL_IF_INVALID_RET_BOOL(expr, jnienv, tagId, writer) \
if ((expr) != OK) { \
jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
"Invalid metadata for tag %s (%x)", (writer)->getTagName(tagId), (tagId)); \
- return; \
+ return false; \
}
+
+#define BAIL_IF_INVALID_RET_NULL_SP(expr, jnienv, tagId, writer) \
+ if ((expr) != OK) { \
+ jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
+ "Invalid metadata for tag %s (%x)", (writer)->getTagName(tagId), (tagId)); \
+ return nullptr; \
+ }
+
+
#define BAIL_IF_INVALID_R(expr, jnienv, tagId, writer) \
if ((expr) != OK) { \
jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
@@ -62,14 +72,14 @@ using namespace img_utils;
return -1; \
}
-
-#define BAIL_IF_EMPTY(entry, jnienv, tagId, writer) \
+#define BAIL_IF_EMPTY_RET_NULL_SP(entry, jnienv, tagId, writer) \
if (entry.count == 0) { \
jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
"Missing metadata fields for tag %s (%x)", (writer)->getTagName(tagId), (tagId)); \
- return; \
+ return nullptr; \
}
+
#define ANDROID_DNGCREATOR_CTX_JNI_ID "mNativeContext"
static struct {
@@ -102,6 +112,26 @@ enum {
TIFF_IFD_GPSINFO = 2,
};
+
+/**
+ * POD container class for GPS tag data.
+ */
+class GpsData {
+public:
+ enum {
+ GPS_VALUE_LENGTH = 6,
+ GPS_REF_LENGTH = 2,
+ GPS_DATE_LENGTH = 11,
+ };
+
+ uint32_t mLatitude[GPS_VALUE_LENGTH];
+ uint32_t mLongitude[GPS_VALUE_LENGTH];
+ uint32_t mTimestamp[GPS_VALUE_LENGTH];
+ uint8_t mLatitudeRef[GPS_REF_LENGTH];
+ uint8_t mLongitudeRef[GPS_REF_LENGTH];
+ uint8_t mDate[GPS_DATE_LENGTH];
+};
+
// ----------------------------------------------------------------------------
/**
@@ -109,8 +139,11 @@ enum {
*/
class NativeContext : public LightRefBase<NativeContext> {
-
public:
+ enum {
+ DATETIME_COUNT = 20,
+ };
+
NativeContext(const CameraMetadata& characteristics, const CameraMetadata& result);
virtual ~NativeContext();
@@ -119,12 +152,28 @@ public:
std::shared_ptr<const CameraMetadata> getCharacteristics() const;
std::shared_ptr<const CameraMetadata> getResult() const;
- uint32_t getThumbnailWidth();
- uint32_t getThumbnailHeight();
- const uint8_t* getThumbnail();
+ uint32_t getThumbnailWidth() const;
+ uint32_t getThumbnailHeight() const;
+ const uint8_t* getThumbnail() const;
+ bool hasThumbnail() const;
bool setThumbnail(const uint8_t* buffer, uint32_t width, uint32_t height);
+ void setOrientation(uint16_t orientation);
+ uint16_t getOrientation() const;
+
+ void setDescription(const String8& desc);
+ String8 getDescription() const;
+ bool hasDescription() const;
+
+ void setGpsData(const GpsData& data);
+ GpsData getGpsData() const;
+ bool hasGpsData() const;
+
+ void setCaptureTime(const String8& formattedCaptureTime);
+ String8 getCaptureTime() const;
+ bool hasCaptureTime() const;
+
private:
Vector<uint8_t> mCurrentThumbnail;
TiffWriter mWriter;
@@ -132,12 +181,21 @@ private:
std::shared_ptr<CameraMetadata> mResult;
uint32_t mThumbnailWidth;
uint32_t mThumbnailHeight;
+ uint16_t mOrientation;
+ bool mThumbnailSet;
+ bool mGpsSet;
+ bool mDescriptionSet;
+ bool mCaptureTimeSet;
+ String8 mDescription;
+ GpsData mGpsData;
+ String8 mFormattedCaptureTime;
};
NativeContext::NativeContext(const CameraMetadata& characteristics, const CameraMetadata& result) :
mCharacteristics(std::make_shared<CameraMetadata>(characteristics)),
mResult(std::make_shared<CameraMetadata>(result)), mThumbnailWidth(0),
- mThumbnailHeight(0) {}
+ mThumbnailHeight(0), mOrientation(0), mThumbnailSet(false), mGpsSet(false),
+ mDescriptionSet(false), mCaptureTimeSet(false) {}
NativeContext::~NativeContext() {}
@@ -153,18 +211,22 @@ std::shared_ptr<const CameraMetadata> NativeContext::getResult() const {
return mResult;
}
-uint32_t NativeContext::getThumbnailWidth() {
+uint32_t NativeContext::getThumbnailWidth() const {
return mThumbnailWidth;
}
-uint32_t NativeContext::getThumbnailHeight() {
+uint32_t NativeContext::getThumbnailHeight() const {
return mThumbnailHeight;
}
-const uint8_t* NativeContext::getThumbnail() {
+const uint8_t* NativeContext::getThumbnail() const {
return mCurrentThumbnail.array();
}
+bool NativeContext::hasThumbnail() const {
+ return mThumbnailSet;
+}
+
bool NativeContext::setThumbnail(const uint8_t* buffer, uint32_t width, uint32_t height) {
mThumbnailWidth = width;
mThumbnailHeight = height;
@@ -177,9 +239,57 @@ bool NativeContext::setThumbnail(const uint8_t* buffer, uint32_t width, uint32_t
uint8_t* thumb = mCurrentThumbnail.editArray();
memcpy(thumb, buffer, size);
+ mThumbnailSet = true;
return true;
}
+void NativeContext::setOrientation(uint16_t orientation) {
+ mOrientation = orientation;
+}
+
+uint16_t NativeContext::getOrientation() const {
+ return mOrientation;
+}
+
+void NativeContext::setDescription(const String8& desc) {
+ mDescription = desc;
+ mDescriptionSet = true;
+}
+
+String8 NativeContext::getDescription() const {
+ return mDescription;
+}
+
+bool NativeContext::hasDescription() const {
+ return mDescriptionSet;
+}
+
+void NativeContext::setGpsData(const GpsData& data) {
+ mGpsData = data;
+ mGpsSet = true;
+}
+
+GpsData NativeContext::getGpsData() const {
+ return mGpsData;
+}
+
+bool NativeContext::hasGpsData() const {
+ return mGpsSet;
+}
+
+void NativeContext::setCaptureTime(const String8& formattedCaptureTime) {
+ mFormattedCaptureTime = formattedCaptureTime;
+ mCaptureTimeSet = true;
+}
+
+String8 NativeContext::getCaptureTime() const {
+ return mFormattedCaptureTime;
+}
+
+bool NativeContext::hasCaptureTime() const {
+ return mCaptureTimeSet;
+}
+
// End of NativeContext
// ----------------------------------------------------------------------------
@@ -211,7 +321,7 @@ private:
JniOutputStream::JniOutputStream(JNIEnv* env, jobject outStream) : mOutputStream(outStream),
mEnv(env) {
mByteArray = env->NewByteArray(BYTE_ARRAY_LENGTH);
- if (mByteArray == NULL) {
+ if (mByteArray == nullptr) {
jniThrowException(env, "java/lang/OutOfMemoryError", "Could not allocate byte array.");
}
}
@@ -286,7 +396,7 @@ private:
JniInputStream::JniInputStream(JNIEnv* env, jobject inStream) : mInStream(inStream), mEnv(env) {
mByteArray = env->NewByteArray(BYTE_ARRAY_LENGTH);
- if (mByteArray == NULL) {
+ if (mByteArray == nullptr) {
jniThrowException(env, "java/lang/OutOfMemoryError", "Could not allocate byte array.");
}
}
@@ -372,7 +482,7 @@ private:
JniInputByteBuffer::JniInputByteBuffer(JNIEnv* env, jobject inBuf) : mInBuf(inBuf), mEnv(env) {
mByteArray = env->NewByteArray(BYTE_ARRAY_LENGTH);
- if (mByteArray == NULL) {
+ if (mByteArray == nullptr) {
jniThrowException(env, "java/lang/OutOfMemoryError", "Could not allocate byte array.");
}
}
@@ -600,6 +710,7 @@ status_t DirectStripSource::writeToStream(Output& stream, uint32_t count) {
return BAD_VALUE;
}
+
if (mPixStride == mBytesPerSample * mSamplesPerPixel
&& mRowStride == mWidth * mBytesPerSample * mSamplesPerPixel) {
ALOGV("%s: Using direct single-pass write for strip.", __FUNCTION__);
@@ -643,37 +754,48 @@ uint32_t DirectStripSource::getIfd() const {
// ----------------------------------------------------------------------------
/**
- * Given a buffer crop rectangle relative to the pixel array size, and the active array crop
- * rectangle for the camera characteristics, set the default crop rectangle in the TiffWriter
- * relative to the buffer crop rectangle origin.
+ * Given a buffer crop rectangle relative to the pixel array size, and the pre-correction active
+ * array crop rectangle for the camera characteristics, set the default crop rectangle in the
+ * TiffWriter relative to the buffer crop rectangle origin.
*/
static status_t calculateAndSetCrop(JNIEnv* env, const CameraMetadata& characteristics,
- uint32_t bufXMin, uint32_t bufYMin, uint32_t bufWidth, uint32_t bufHeight,
- TiffWriter* writer) {
+ uint32_t bufWidth, uint32_t bufHeight, sp<TiffWriter> writer) {
camera_metadata_ro_entry entry =
- characteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
+ characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
uint32_t xmin = static_cast<uint32_t>(entry.data.i32[0]);
uint32_t ymin = static_cast<uint32_t>(entry.data.i32[1]);
uint32_t width = static_cast<uint32_t>(entry.data.i32[2]);
uint32_t height = static_cast<uint32_t>(entry.data.i32[3]);
+ const uint32_t margin = 8; // Default margin recommended by Adobe for interpolation.
+
+ // Crop based on pre-correction array for pixel array
uint32_t aLeft = xmin;
uint32_t aTop = ymin;
uint32_t aRight = xmin + width;
uint32_t aBottom = ymin + height;
- const uint32_t margin = 8; // Default margin recommended by Adobe for interpolation.
-
- uint32_t bLeft = bufXMin + margin;
- uint32_t bTop = bufYMin + margin;
- uint32_t bRight = bufXMin + bufWidth - margin;
- uint32_t bBottom = bufYMin + bufHeight - margin;
+ // 8 pixel border crop for pixel array dimens
+ uint32_t bLeft = margin;
+ uint32_t bTop = margin;
+ uint32_t bRight = bufWidth - margin;
+ uint32_t bBottom = bufHeight - margin;
+ // Set the crop to be the intersection of the two rectangles
uint32_t defaultCropOrigin[] = {std::max(aLeft, bLeft), std::max(aTop, bTop)};
uint32_t defaultCropSize[] = {std::min(aRight, bRight) - defaultCropOrigin[0],
std::min(aBottom, bBottom) - defaultCropOrigin[1]};
+ // If using buffers with pre-correction array dimens, switch to 8 pixel border crop
+ // relative to the pixel array dimens
+ if (bufWidth == width && bufHeight == height) {
+ defaultCropOrigin[0] = xmin + margin;
+ defaultCropOrigin[1] = ymin + margin;
+ defaultCropSize[0] = width - margin;
+ defaultCropSize[1] = height - margin;
+ }
+
BAIL_IF_INVALID_R(writer->addEntry(TAG_DEFAULTCROPORIGIN, 2, defaultCropOrigin,
TIFF_IFD_0), env, TAG_DEFAULTCROPORIGIN, writer);
BAIL_IF_INVALID_R(writer->addEntry(TAG_DEFAULTCROPSIZE, 2, defaultCropSize,
@@ -682,9 +804,8 @@ static status_t calculateAndSetCrop(JNIEnv* env, const CameraMetadata& character
return OK;
}
-static bool validateDngHeader(JNIEnv* env, TiffWriter* writer,
+static bool validateDngHeader(JNIEnv* env, sp<TiffWriter> writer,
const CameraMetadata& characteristics, jint width, jint height) {
- // TODO: handle lens shading map, etc. conversions for other raw buffer sizes.
if (width <= 0) {
jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", \
"Image width %d is invalid", width);
@@ -710,20 +831,7 @@ static bool validateDngHeader(JNIEnv* env, TiffWriter* writer,
bool matchesPixelArray = (pWidth == width && pHeight == height);
bool matchesPreCorrectionArray = (cWidth == width && cHeight == height);
- if (matchesPixelArray) {
- if (calculateAndSetCrop(env, characteristics, 0, 0, static_cast<uint32_t>(pWidth),
- static_cast<uint32_t>(pHeight), writer) != OK) {
- return false;
- }
- } else if (matchesPreCorrectionArray) {
- if (calculateAndSetCrop(env, characteristics,
- static_cast<uint32_t>(preCorrectionEntry.data.i32[0]),
- static_cast<uint32_t>(preCorrectionEntry.data.i32[1]),
- static_cast<uint32_t>(preCorrectionEntry.data.i32[2]),
- static_cast<uint32_t>(preCorrectionEntry.data.i32[3]), writer) != OK) {
- return false;
- }
- } else {
+ if (!(matchesPixelArray || matchesPreCorrectionArray)) {
jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", \
"Image dimensions (w=%d,h=%d) are invalid, must match either the pixel "
"array size (w=%d, h=%d) or the pre-correction array size (w=%d, h=%d)",
@@ -734,12 +842,12 @@ static bool validateDngHeader(JNIEnv* env, TiffWriter* writer,
return true;
}
-static status_t moveEntries(TiffWriter* writer, uint32_t ifdFrom, uint32_t ifdTo,
+static status_t moveEntries(sp<TiffWriter> writer, uint32_t ifdFrom, uint32_t ifdTo,
const Vector<uint16_t>& entries) {
for (size_t i = 0; i < entries.size(); ++i) {
uint16_t tagId = entries[i];
sp<TiffEntry> entry = writer->getEntry(tagId, ifdFrom);
- if (entry == NULL) {
+ if (entry.get() == nullptr) {
ALOGE("%s: moveEntries failed, entry %u not found in IFD %u", __FUNCTION__, tagId,
ifdFrom);
return BAD_VALUE;
@@ -881,7 +989,7 @@ static void DngCreator_setNativeContext(JNIEnv* env, jobject thiz, sp<NativeCont
ALOGV("%s:", __FUNCTION__);
NativeContext* current = DngCreator_getNativeContext(env, thiz);
- if (context != NULL) {
+ if (context != nullptr) {
context->incStrong((void*) DngCreator_setNativeContext);
}
@@ -893,15 +1001,6 @@ static void DngCreator_setNativeContext(JNIEnv* env, jobject thiz, sp<NativeCont
reinterpret_cast<jlong>(context.get()));
}
-static TiffWriter* DngCreator_getCreator(JNIEnv* env, jobject thiz) {
- ALOGV("%s:", __FUNCTION__);
- NativeContext* current = DngCreator_getNativeContext(env, thiz);
- if (current) {
- return current->getWriter();
- }
- return NULL;
-}
-
static void DngCreator_nativeClassInit(JNIEnv* env, jclass clazz) {
ALOGV("%s:", __FUNCTION__);
@@ -938,7 +1037,62 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
}
sp<NativeContext> nativeContext = new NativeContext(characteristics, results);
- TiffWriter* writer = nativeContext->getWriter();
+
+ const char* captureTime = env->GetStringUTFChars(formattedCaptureTime, nullptr);
+
+ size_t len = strlen(captureTime) + 1;
+ if (len != NativeContext::DATETIME_COUNT) {
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "Formatted capture time string length is not required 20 characters");
+ return;
+ }
+
+ nativeContext->setCaptureTime(String8(captureTime));
+
+ DngCreator_setNativeContext(env, thiz, nativeContext);
+}
+
+static sp<TiffWriter> DngCreator_setup(JNIEnv* env, jobject thiz, uint32_t imageWidth,
+ uint32_t imageHeight) {
+
+ NativeContext* nativeContext = DngCreator_getNativeContext(env, thiz);
+
+ if (nativeContext == nullptr) {
+ jniThrowException(env, "java/lang/AssertionError",
+ "No native context, must call init before other operations.");
+ return nullptr;
+ }
+
+ CameraMetadata characteristics = *(nativeContext->getCharacteristics());
+ CameraMetadata results = *(nativeContext->getResult());
+
+ sp<TiffWriter> writer = new TiffWriter();
+
+ uint32_t preWidth = 0;
+ uint32_t preHeight = 0;
+ {
+ // Check dimensions
+ camera_metadata_entry entry =
+ characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_IMAGEWIDTH, writer);
+ preWidth = static_cast<uint32_t>(entry.data.i32[2]);
+ preHeight = static_cast<uint32_t>(entry.data.i32[3]);
+
+ camera_metadata_entry pixelArrayEntry =
+ characteristics.find(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE);
+ uint32_t pixWidth = static_cast<uint32_t>(pixelArrayEntry.data.i32[0]);
+ uint32_t pixHeight = static_cast<uint32_t>(pixelArrayEntry.data.i32[1]);
+
+ if (!((imageWidth == preWidth && imageHeight == preHeight) ||
+ (imageWidth == pixWidth && imageHeight == pixHeight))) {
+ jniThrowException(env, "java/lang/AssertionError",
+ "Height and width of imate buffer did not match height and width of"
+ "either the preCorrectionActiveArraySize or the pixelArraySize.");
+ return nullptr;
+ }
+ }
+
+
writer->addIfd(TIFF_IFD_0);
@@ -946,8 +1100,6 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
const uint32_t samplesPerPixel = 1;
const uint32_t bitsPerSample = BITS_PER_SAMPLE;
- uint32_t imageWidth = 0;
- uint32_t imageHeight = 0;
OpcodeListBuilder::CfaLayout opcodeCfaLayout = OpcodeListBuilder::CFA_RGGB;
uint8_t cfaPlaneColor[3] = {0, 1, 2};
@@ -961,93 +1113,86 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
{
// Set orientation
uint16_t orientation = 1; // Normal
- BAIL_IF_INVALID(writer->addEntry(TAG_ORIENTATION, 1, &orientation, TIFF_IFD_0), env,
- TAG_ORIENTATION, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_ORIENTATION, 1, &orientation, TIFF_IFD_0),
+ env, TAG_ORIENTATION, writer);
}
{
// Set subfiletype
uint32_t subfileType = 0; // Main image
- BAIL_IF_INVALID(writer->addEntry(TAG_NEWSUBFILETYPE, 1, &subfileType, TIFF_IFD_0), env,
- TAG_NEWSUBFILETYPE, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_NEWSUBFILETYPE, 1, &subfileType,
+ TIFF_IFD_0), env, TAG_NEWSUBFILETYPE, writer);
}
{
// Set bits per sample
uint16_t bits = static_cast<uint16_t>(bitsPerSample);
- BAIL_IF_INVALID(writer->addEntry(TAG_BITSPERSAMPLE, 1, &bits, TIFF_IFD_0), env,
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_BITSPERSAMPLE, 1, &bits, TIFF_IFD_0), env,
TAG_BITSPERSAMPLE, writer);
}
{
// Set compression
uint16_t compression = 1; // None
- BAIL_IF_INVALID(writer->addEntry(TAG_COMPRESSION, 1, &compression, TIFF_IFD_0), env,
- TAG_COMPRESSION, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_COMPRESSION, 1, &compression,
+ TIFF_IFD_0), env, TAG_COMPRESSION, writer);
}
{
// Set dimensions
- camera_metadata_entry entry =
- characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
- BAIL_IF_EMPTY(entry, env, TAG_IMAGEWIDTH, writer);
- uint32_t width = static_cast<uint32_t>(entry.data.i32[2]);
- uint32_t height = static_cast<uint32_t>(entry.data.i32[3]);
- BAIL_IF_INVALID(writer->addEntry(TAG_IMAGEWIDTH, 1, &width, TIFF_IFD_0), env,
- TAG_IMAGEWIDTH, writer);
- BAIL_IF_INVALID(writer->addEntry(TAG_IMAGELENGTH, 1, &height, TIFF_IFD_0), env,
- TAG_IMAGELENGTH, writer);
- imageWidth = width;
- imageHeight = height;
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_IMAGEWIDTH, 1, &imageWidth, TIFF_IFD_0),
+ env, TAG_IMAGEWIDTH, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_IMAGELENGTH, 1, &imageHeight, TIFF_IFD_0),
+ env, TAG_IMAGELENGTH, writer);
}
{
// Set photometric interpretation
uint16_t interpretation = 32803; // CFA
- BAIL_IF_INVALID(writer->addEntry(TAG_PHOTOMETRICINTERPRETATION, 1, &interpretation,
- TIFF_IFD_0), env, TAG_PHOTOMETRICINTERPRETATION, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_PHOTOMETRICINTERPRETATION, 1,
+ &interpretation, TIFF_IFD_0), env, TAG_PHOTOMETRICINTERPRETATION, writer);
}
{
// Set blacklevel tags
camera_metadata_entry entry =
characteristics.find(ANDROID_SENSOR_BLACK_LEVEL_PATTERN);
- BAIL_IF_EMPTY(entry, env, TAG_BLACKLEVEL, writer);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_BLACKLEVEL, writer);
const uint32_t* blackLevel = reinterpret_cast<const uint32_t*>(entry.data.i32);
- BAIL_IF_INVALID(writer->addEntry(TAG_BLACKLEVEL, entry.count, blackLevel, TIFF_IFD_0), env,
- TAG_BLACKLEVEL, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_BLACKLEVEL, entry.count, blackLevel,
+ TIFF_IFD_0), env, TAG_BLACKLEVEL, writer);
uint16_t repeatDim[2] = {2, 2};
- BAIL_IF_INVALID(writer->addEntry(TAG_BLACKLEVELREPEATDIM, 2, repeatDim, TIFF_IFD_0), env,
- TAG_BLACKLEVELREPEATDIM, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_BLACKLEVELREPEATDIM, 2, repeatDim,
+ TIFF_IFD_0), env, TAG_BLACKLEVELREPEATDIM, writer);
}
{
// Set samples per pixel
uint16_t samples = static_cast<uint16_t>(samplesPerPixel);
- BAIL_IF_INVALID(writer->addEntry(TAG_SAMPLESPERPIXEL, 1, &samples, TIFF_IFD_0),
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_SAMPLESPERPIXEL, 1, &samples, TIFF_IFD_0),
env, TAG_SAMPLESPERPIXEL, writer);
}
{
// Set planar configuration
uint16_t config = 1; // Chunky
- BAIL_IF_INVALID(writer->addEntry(TAG_PLANARCONFIGURATION, 1, &config, TIFF_IFD_0),
- env, TAG_PLANARCONFIGURATION, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_PLANARCONFIGURATION, 1, &config,
+ TIFF_IFD_0), env, TAG_PLANARCONFIGURATION, writer);
}
{
// Set CFA pattern dimensions
uint16_t repeatDim[2] = {2, 2};
- BAIL_IF_INVALID(writer->addEntry(TAG_CFAREPEATPATTERNDIM, 2, repeatDim, TIFF_IFD_0),
- env, TAG_CFAREPEATPATTERNDIM, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CFAREPEATPATTERNDIM, 2, repeatDim,
+ TIFF_IFD_0), env, TAG_CFAREPEATPATTERNDIM, writer);
}
{
// Set CFA pattern
camera_metadata_entry entry =
characteristics.find(ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT);
- BAIL_IF_EMPTY(entry, env, TAG_CFAPATTERN, writer);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_CFAPATTERN, writer);
const int cfaLength = 4;
cfaEnum = entry.data.u8[0];
@@ -1057,30 +1202,30 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
"Invalid metadata for tag %d", TAG_CFAPATTERN);
}
- BAIL_IF_INVALID(writer->addEntry(TAG_CFAPATTERN, cfaLength, cfa, TIFF_IFD_0), env,
- TAG_CFAPATTERN, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CFAPATTERN, cfaLength, cfa, TIFF_IFD_0),
+ env, TAG_CFAPATTERN, writer);
opcodeCfaLayout = convertCFAEnumToOpcodeLayout(cfaEnum);
}
{
// Set CFA plane color
- BAIL_IF_INVALID(writer->addEntry(TAG_CFAPLANECOLOR, 3, cfaPlaneColor, TIFF_IFD_0),
- env, TAG_CFAPLANECOLOR, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CFAPLANECOLOR, 3, cfaPlaneColor,
+ TIFF_IFD_0), env, TAG_CFAPLANECOLOR, writer);
}
{
// Set CFA layout
uint16_t cfaLayout = 1;
- BAIL_IF_INVALID(writer->addEntry(TAG_CFALAYOUT, 1, &cfaLayout, TIFF_IFD_0),
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CFALAYOUT, 1, &cfaLayout, TIFF_IFD_0),
env, TAG_CFALAYOUT, writer);
}
{
// image description
uint8_t imageDescription = '\0'; // empty
- BAIL_IF_INVALID(writer->addEntry(TAG_IMAGEDESCRIPTION, 1, &imageDescription, TIFF_IFD_0),
- env, TAG_IMAGEDESCRIPTION, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_IMAGEDESCRIPTION, 1, &imageDescription,
+ TIFF_IFD_0), env, TAG_IMAGEDESCRIPTION, writer);
}
{
@@ -1091,8 +1236,8 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
property_get("ro.product.manufacturer", manufacturer, "");
uint32_t count = static_cast<uint32_t>(strlen(manufacturer)) + 1;
- BAIL_IF_INVALID(writer->addEntry(TAG_MAKE, count, reinterpret_cast<uint8_t*>(manufacturer),
- TIFF_IFD_0), env, TAG_MAKE, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_MAKE, count,
+ reinterpret_cast<uint8_t*>(manufacturer), TIFF_IFD_0), env, TAG_MAKE, writer);
}
{
@@ -1103,23 +1248,23 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
property_get("ro.product.model", model, "");
uint32_t count = static_cast<uint32_t>(strlen(model)) + 1;
- BAIL_IF_INVALID(writer->addEntry(TAG_MODEL, count, reinterpret_cast<uint8_t*>(model),
- TIFF_IFD_0), env, TAG_MODEL, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_MODEL, count,
+ reinterpret_cast<uint8_t*>(model), TIFF_IFD_0), env, TAG_MODEL, writer);
}
{
// x resolution
uint32_t xres[] = { 72, 1 }; // default 72 ppi
- BAIL_IF_INVALID(writer->addEntry(TAG_XRESOLUTION, 1, xres, TIFF_IFD_0),
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_XRESOLUTION, 1, xres, TIFF_IFD_0),
env, TAG_XRESOLUTION, writer);
// y resolution
uint32_t yres[] = { 72, 1 }; // default 72 ppi
- BAIL_IF_INVALID(writer->addEntry(TAG_YRESOLUTION, 1, yres, TIFF_IFD_0),
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_YRESOLUTION, 1, yres, TIFF_IFD_0),
env, TAG_YRESOLUTION, writer);
uint16_t unit = 2; // inches
- BAIL_IF_INVALID(writer->addEntry(TAG_RESOLUTIONUNIT, 1, &unit, TIFF_IFD_0),
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_RESOLUTIONUNIT, 1, &unit, TIFF_IFD_0),
env, TAG_RESOLUTIONUNIT, writer);
}
@@ -1128,52 +1273,41 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
char software[PROPERTY_VALUE_MAX];
property_get("ro.build.fingerprint", software, "");
uint32_t count = static_cast<uint32_t>(strlen(software)) + 1;
- BAIL_IF_INVALID(writer->addEntry(TAG_SOFTWARE, count, reinterpret_cast<uint8_t*>(software),
- TIFF_IFD_0), env, TAG_SOFTWARE, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_SOFTWARE, count,
+ reinterpret_cast<uint8_t*>(software), TIFF_IFD_0), env, TAG_SOFTWARE, writer);
}
- {
+ if (nativeContext->hasCaptureTime()) {
// datetime
- const size_t DATETIME_COUNT = 20;
- const char* captureTime = env->GetStringUTFChars(formattedCaptureTime, NULL);
-
- size_t len = strlen(captureTime) + 1;
- if (len != DATETIME_COUNT) {
- jniThrowException(env, "java/lang/IllegalArgumentException",
- "Timestamp string length is not required 20 characters");
- return;
- }
+ String8 captureTime = nativeContext->getCaptureTime();
- if (writer->addEntry(TAG_DATETIME, DATETIME_COUNT,
- reinterpret_cast<const uint8_t*>(captureTime), TIFF_IFD_0) != OK) {
- env->ReleaseStringUTFChars(formattedCaptureTime, captureTime);
+ if (writer->addEntry(TAG_DATETIME, NativeContext::DATETIME_COUNT,
+ reinterpret_cast<const uint8_t*>(captureTime.string()), TIFF_IFD_0) != OK) {
jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
"Invalid metadata for tag %x", TAG_DATETIME);
- return;
+ return nullptr;
}
// datetime original
- if (writer->addEntry(TAG_DATETIMEORIGINAL, DATETIME_COUNT,
- reinterpret_cast<const uint8_t*>(captureTime), TIFF_IFD_0) != OK) {
- env->ReleaseStringUTFChars(formattedCaptureTime, captureTime);
+ if (writer->addEntry(TAG_DATETIMEORIGINAL, NativeContext::DATETIME_COUNT,
+ reinterpret_cast<const uint8_t*>(captureTime.string()), TIFF_IFD_0) != OK) {
jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
"Invalid metadata for tag %x", TAG_DATETIMEORIGINAL);
- return;
+ return nullptr;
}
- env->ReleaseStringUTFChars(formattedCaptureTime, captureTime);
}
{
// TIFF/EP standard id
uint8_t standardId[] = { 1, 0, 0, 0 };
- BAIL_IF_INVALID(writer->addEntry(TAG_TIFFEPSTANDARDID, 4, standardId,
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_TIFFEPSTANDARDID, 4, standardId,
TIFF_IFD_0), env, TAG_TIFFEPSTANDARDID, writer);
}
{
// copyright
uint8_t copyright = '\0'; // empty
- BAIL_IF_INVALID(writer->addEntry(TAG_COPYRIGHT, 1, &copyright,
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_COPYRIGHT, 1, &copyright,
TIFF_IFD_0), env, TAG_COPYRIGHT, writer);
}
@@ -1181,7 +1315,7 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
// exposure time
camera_metadata_entry entry =
results.find(ANDROID_SENSOR_EXPOSURE_TIME);
- BAIL_IF_EMPTY(entry, env, TAG_EXPOSURETIME, writer);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_EXPOSURETIME, writer);
int64_t exposureTime = *(entry.data.i64);
@@ -1189,7 +1323,7 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
// Should be unreachable
jniThrowException(env, "java/lang/IllegalArgumentException",
"Negative exposure time in metadata");
- return;
+ return nullptr;
}
// Ensure exposure time doesn't overflow (for exposures > 4s)
@@ -1201,12 +1335,12 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
// Should be unreachable
jniThrowException(env, "java/lang/IllegalArgumentException",
"Exposure time too long");
- return;
+ return nullptr;
}
}
uint32_t exposure[] = { static_cast<uint32_t>(exposureTime), denominator };
- BAIL_IF_INVALID(writer->addEntry(TAG_EXPOSURETIME, 1, exposure,
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_EXPOSURETIME, 1, exposure,
TIFF_IFD_0), env, TAG_EXPOSURETIME, writer);
}
@@ -1215,13 +1349,13 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
// ISO speed ratings
camera_metadata_entry entry =
results.find(ANDROID_SENSOR_SENSITIVITY);
- BAIL_IF_EMPTY(entry, env, TAG_ISOSPEEDRATINGS, writer);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_ISOSPEEDRATINGS, writer);
int32_t tempIso = *(entry.data.i32);
if (tempIso < 0) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"Negative ISO value");
- return;
+ return nullptr;
}
if (tempIso > UINT16_MAX) {
@@ -1230,7 +1364,7 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
}
uint16_t iso = static_cast<uint16_t>(tempIso);
- BAIL_IF_INVALID(writer->addEntry(TAG_ISOSPEEDRATINGS, 1, &iso,
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_ISOSPEEDRATINGS, 1, &iso,
TIFF_IFD_0), env, TAG_ISOSPEEDRATINGS, writer);
}
@@ -1238,10 +1372,10 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
// focal length
camera_metadata_entry entry =
results.find(ANDROID_LENS_FOCAL_LENGTH);
- BAIL_IF_EMPTY(entry, env, TAG_FOCALLENGTH, writer);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_FOCALLENGTH, writer);
uint32_t focalLength[] = { static_cast<uint32_t>(*(entry.data.f) * 100), 100 };
- BAIL_IF_INVALID(writer->addEntry(TAG_FOCALLENGTH, 1, focalLength,
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_FOCALLENGTH, 1, focalLength,
TIFF_IFD_0), env, TAG_FOCALLENGTH, writer);
}
@@ -1249,39 +1383,39 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
// f number
camera_metadata_entry entry =
results.find(ANDROID_LENS_APERTURE);
- BAIL_IF_EMPTY(entry, env, TAG_FNUMBER, writer);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_FNUMBER, writer);
uint32_t fnum[] = { static_cast<uint32_t>(*(entry.data.f) * 100), 100 };
- BAIL_IF_INVALID(writer->addEntry(TAG_FNUMBER, 1, fnum,
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_FNUMBER, 1, fnum,
TIFF_IFD_0), env, TAG_FNUMBER, writer);
}
{
// Set DNG version information
uint8_t version[4] = {1, 4, 0, 0};
- BAIL_IF_INVALID(writer->addEntry(TAG_DNGVERSION, 4, version, TIFF_IFD_0),
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_DNGVERSION, 4, version, TIFF_IFD_0),
env, TAG_DNGVERSION, writer);
uint8_t backwardVersion[4] = {1, 1, 0, 0};
- BAIL_IF_INVALID(writer->addEntry(TAG_DNGBACKWARDVERSION, 4, backwardVersion, TIFF_IFD_0),
- env, TAG_DNGBACKWARDVERSION, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_DNGBACKWARDVERSION, 4, backwardVersion,
+ TIFF_IFD_0), env, TAG_DNGBACKWARDVERSION, writer);
}
{
// Set whitelevel
camera_metadata_entry entry =
characteristics.find(ANDROID_SENSOR_INFO_WHITE_LEVEL);
- BAIL_IF_EMPTY(entry, env, TAG_WHITELEVEL, writer);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_WHITELEVEL, writer);
uint32_t whiteLevel = static_cast<uint32_t>(entry.data.i32[0]);
- BAIL_IF_INVALID(writer->addEntry(TAG_WHITELEVEL, 1, &whiteLevel, TIFF_IFD_0), env,
- TAG_WHITELEVEL, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_WHITELEVEL, 1, &whiteLevel, TIFF_IFD_0),
+ env, TAG_WHITELEVEL, writer);
}
{
// Set default scale
uint32_t defaultScale[4] = {1, 1, 1, 1};
- BAIL_IF_INVALID(writer->addEntry(TAG_DEFAULTSCALE, 2, defaultScale, TIFF_IFD_0),
- env, TAG_DEFAULTSCALE, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_DEFAULTSCALE, 2, defaultScale,
+ TIFF_IFD_0), env, TAG_DEFAULTSCALE, writer);
}
bool singleIlluminant = false;
@@ -1289,7 +1423,7 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
// Set calibration illuminants
camera_metadata_entry entry1 =
characteristics.find(ANDROID_SENSOR_REFERENCE_ILLUMINANT1);
- BAIL_IF_EMPTY(entry1, env, TAG_CALIBRATIONILLUMINANT1, writer);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry1, env, TAG_CALIBRATIONILLUMINANT1, writer);
camera_metadata_entry entry2 =
characteristics.find(ANDROID_SENSOR_REFERENCE_ILLUMINANT2);
if (entry2.count == 0) {
@@ -1297,12 +1431,12 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
}
uint16_t ref1 = entry1.data.u8[0];
- BAIL_IF_INVALID(writer->addEntry(TAG_CALIBRATIONILLUMINANT1, 1, &ref1,
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CALIBRATIONILLUMINANT1, 1, &ref1,
TIFF_IFD_0), env, TAG_CALIBRATIONILLUMINANT1, writer);
if (!singleIlluminant) {
uint16_t ref2 = entry2.data.u8[0];
- BAIL_IF_INVALID(writer->addEntry(TAG_CALIBRATIONILLUMINANT2, 1, &ref2,
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CALIBRATIONILLUMINANT2, 1, &ref2,
TIFF_IFD_0), env, TAG_CALIBRATIONILLUMINANT2, writer);
}
}
@@ -1311,7 +1445,7 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
// Set color transforms
camera_metadata_entry entry1 =
characteristics.find(ANDROID_SENSOR_COLOR_TRANSFORM1);
- BAIL_IF_EMPTY(entry1, env, TAG_COLORMATRIX1, writer);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry1, env, TAG_COLORMATRIX1, writer);
int32_t colorTransform1[entry1.count * 2];
@@ -1321,12 +1455,12 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
colorTransform1[ctr++] = entry1.data.r[i].denominator;
}
- BAIL_IF_INVALID(writer->addEntry(TAG_COLORMATRIX1, entry1.count, colorTransform1,
- TIFF_IFD_0), env, TAG_COLORMATRIX1, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_COLORMATRIX1, entry1.count,
+ colorTransform1, TIFF_IFD_0), env, TAG_COLORMATRIX1, writer);
if (!singleIlluminant) {
camera_metadata_entry entry2 = characteristics.find(ANDROID_SENSOR_COLOR_TRANSFORM2);
- BAIL_IF_EMPTY(entry2, env, TAG_COLORMATRIX2, writer);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry2, env, TAG_COLORMATRIX2, writer);
int32_t colorTransform2[entry2.count * 2];
ctr = 0;
@@ -1335,8 +1469,8 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
colorTransform2[ctr++] = entry2.data.r[i].denominator;
}
- BAIL_IF_INVALID(writer->addEntry(TAG_COLORMATRIX2, entry2.count, colorTransform2,
- TIFF_IFD_0), env, TAG_COLORMATRIX2, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_COLORMATRIX2, entry2.count,
+ colorTransform2, TIFF_IFD_0), env, TAG_COLORMATRIX2, writer);
}
}
@@ -1344,7 +1478,7 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
// Set calibration transforms
camera_metadata_entry entry1 =
characteristics.find(ANDROID_SENSOR_CALIBRATION_TRANSFORM1);
- BAIL_IF_EMPTY(entry1, env, TAG_CAMERACALIBRATION1, writer);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry1, env, TAG_CAMERACALIBRATION1, writer);
int32_t calibrationTransform1[entry1.count * 2];
@@ -1354,13 +1488,13 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
calibrationTransform1[ctr++] = entry1.data.r[i].denominator;
}
- BAIL_IF_INVALID(writer->addEntry(TAG_CAMERACALIBRATION1, entry1.count,
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CAMERACALIBRATION1, entry1.count,
calibrationTransform1, TIFF_IFD_0), env, TAG_CAMERACALIBRATION1, writer);
if (!singleIlluminant) {
camera_metadata_entry entry2 =
characteristics.find(ANDROID_SENSOR_CALIBRATION_TRANSFORM2);
- BAIL_IF_EMPTY(entry2, env, TAG_CAMERACALIBRATION2, writer);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry2, env, TAG_CAMERACALIBRATION2, writer);
int32_t calibrationTransform2[entry2.count * 2];
ctr = 0;
@@ -1369,7 +1503,7 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
calibrationTransform2[ctr++] = entry2.data.r[i].denominator;
}
- BAIL_IF_INVALID(writer->addEntry(TAG_CAMERACALIBRATION2, entry2.count,
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CAMERACALIBRATION2, entry2.count,
calibrationTransform2, TIFF_IFD_0), env, TAG_CAMERACALIBRATION2, writer);
}
}
@@ -1378,7 +1512,7 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
// Set forward transforms
camera_metadata_entry entry1 =
characteristics.find(ANDROID_SENSOR_FORWARD_MATRIX1);
- BAIL_IF_EMPTY(entry1, env, TAG_FORWARDMATRIX1, writer);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry1, env, TAG_FORWARDMATRIX1, writer);
int32_t forwardTransform1[entry1.count * 2];
@@ -1388,13 +1522,13 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
forwardTransform1[ctr++] = entry1.data.r[i].denominator;
}
- BAIL_IF_INVALID(writer->addEntry(TAG_FORWARDMATRIX1, entry1.count, forwardTransform1,
- TIFF_IFD_0), env, TAG_FORWARDMATRIX1, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_FORWARDMATRIX1, entry1.count,
+ forwardTransform1, TIFF_IFD_0), env, TAG_FORWARDMATRIX1, writer);
if (!singleIlluminant) {
camera_metadata_entry entry2 =
characteristics.find(ANDROID_SENSOR_FORWARD_MATRIX2);
- BAIL_IF_EMPTY(entry2, env, TAG_FORWARDMATRIX2, writer);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry2, env, TAG_FORWARDMATRIX2, writer);
int32_t forwardTransform2[entry2.count * 2];
ctr = 0;
@@ -1403,8 +1537,8 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
forwardTransform2[ctr++] = entry2.data.r[i].denominator;
}
- BAIL_IF_INVALID(writer->addEntry(TAG_FORWARDMATRIX2, entry2.count, forwardTransform2,
- TIFF_IFD_0), env, TAG_FORWARDMATRIX2, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_FORWARDMATRIX2, entry2.count,
+ forwardTransform2, TIFF_IFD_0), env, TAG_FORWARDMATRIX2, writer);
}
}
@@ -1412,7 +1546,7 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
// Set camera neutral
camera_metadata_entry entry =
results.find(ANDROID_SENSOR_NEUTRAL_COLOR_POINT);
- BAIL_IF_EMPTY(entry, env, TAG_ASSHOTNEUTRAL, writer);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_ASSHOTNEUTRAL, writer);
uint32_t cameraNeutral[entry.count * 2];
size_t ctr = 0;
@@ -1423,33 +1557,27 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
static_cast<uint32_t>(entry.data.r[i].denominator);
}
- BAIL_IF_INVALID(writer->addEntry(TAG_ASSHOTNEUTRAL, entry.count, cameraNeutral,
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_ASSHOTNEUTRAL, entry.count, cameraNeutral,
TIFF_IFD_0), env, TAG_ASSHOTNEUTRAL, writer);
}
- {
- // Setup data strips
- // TODO: Switch to tiled implementation.
- if (writer->addStrip(TIFF_IFD_0) != OK) {
- ALOGE("%s: Could not setup strip tags.", __FUNCTION__);
- jniThrowException(env, "java/lang/IllegalStateException",
- "Failed to setup strip tags.");
- return;
- }
- }
{
// Set dimensions
+ if (calculateAndSetCrop(env, characteristics, imageWidth, imageHeight, writer) != OK) {
+ return nullptr;
+ }
camera_metadata_entry entry =
characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
- BAIL_IF_EMPTY(entry, env, TAG_DEFAULTCROPSIZE, writer);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_DEFAULTCROPSIZE, writer);
uint32_t xmin = static_cast<uint32_t>(entry.data.i32[0]);
uint32_t ymin = static_cast<uint32_t>(entry.data.i32[1]);
uint32_t width = static_cast<uint32_t>(entry.data.i32[2]);
uint32_t height = static_cast<uint32_t>(entry.data.i32[3]);
- if (calculateAndSetCrop(env, characteristics, xmin, ymin, width, height, writer) != OK) {
- return;
- }
+
+ uint32_t activeArea[] = {ymin, xmin, ymin + height, xmin + width};
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_ACTIVEAREA, 4, activeArea, TIFF_IFD_0),
+ env, TAG_ACTIVEAREA, writer);
}
{
@@ -1469,7 +1597,7 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
cameraModel += "-";
cameraModel += brand;
- BAIL_IF_INVALID(writer->addEntry(TAG_UNIQUECAMERAMODEL, cameraModel.size() + 1,
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_UNIQUECAMERAMODEL, cameraModel.size() + 1,
reinterpret_cast<const uint8_t*>(cameraModel.string()), TIFF_IFD_0), env,
TAG_UNIQUECAMERAMODEL, writer);
}
@@ -1486,7 +1614,7 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
if ((err = convertCFA(cfaEnum, /*out*/cfaOut)) != OK) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"Invalid CFA from camera characteristics");
- return;
+ return nullptr;
}
double noiseProfile[numPlaneColors * 2];
@@ -1500,8 +1628,9 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
if ((err = generateNoiseProfile(entry.data.d, cfaOut, numCfaChannels,
cfaPlaneColor, numPlaneColors, /*out*/ noiseProfile)) == OK) {
- BAIL_IF_INVALID(writer->addEntry(TAG_NOISEPROFILE, numPlaneColors * 2,
- noiseProfile, TIFF_IFD_0), env, TAG_NOISEPROFILE, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_NOISEPROFILE,
+ numPlaneColors * 2, noiseProfile, TIFF_IFD_0), env, TAG_NOISEPROFILE,
+ writer);
} else {
ALOGW("%s: Error converting coefficients for noise profile, no noise profile"
" tag written...", __FUNCTION__);
@@ -1533,19 +1662,26 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
camera_metadata_entry entry2 =
results.find(ANDROID_STATISTICS_LENS_SHADING_MAP);
+ camera_metadata_entry entry =
+ characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_IMAGEWIDTH, writer);
+ uint32_t xmin = static_cast<uint32_t>(entry.data.i32[0]);
+ uint32_t ymin = static_cast<uint32_t>(entry.data.i32[1]);
+ uint32_t width = static_cast<uint32_t>(entry.data.i32[2]);
+ uint32_t height = static_cast<uint32_t>(entry.data.i32[3]);
if (entry2.count > 0 && entry2.count == lsmWidth * lsmHeight * 4) {
err = builder.addGainMapsForMetadata(lsmWidth,
lsmHeight,
- 0,
- 0,
- imageHeight,
- imageWidth,
+ ymin,
+ xmin,
+ height,
+ width,
opcodeCfaLayout,
entry2.data.f);
if (err != OK) {
ALOGE("%s: Could not add Lens shading map.", __FUNCTION__);
jniThrowRuntimeException(env, "failed to add lens shading map.");
- return;
+ return nullptr;
}
}
@@ -1553,14 +1689,14 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
uint8_t opcodeListBuf[listSize];
err = builder.buildOpList(opcodeListBuf);
if (err == OK) {
- BAIL_IF_INVALID(writer->addEntry(TAG_OPCODELIST2, listSize, opcodeListBuf,
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_OPCODELIST2, listSize, opcodeListBuf,
TIFF_IFD_0), env, TAG_OPCODELIST2, writer);
} else {
ALOGE("%s: Could not build list of opcodes for distortion correction and lens shading"
"map.", __FUNCTION__);
jniThrowRuntimeException(env, "failed to construct opcode list for distortion"
" correction and lens shading map");
- return;
+ return nullptr;
}
}
@@ -1578,12 +1714,12 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
if (entry3.count == 6 && entry4.count == 5) {
float cx = entry4.data.f[/*c_x*/2];
float cy = entry4.data.f[/*c_y*/3];
- err = builder.addWarpRectilinearForMetadata(entry3.data.f, imageWidth, imageHeight, cx,
+ err = builder.addWarpRectilinearForMetadata(entry3.data.f, preWidth, preHeight, cx,
cy);
if (err != OK) {
ALOGE("%s: Could not add distortion correction.", __FUNCTION__);
jniThrowRuntimeException(env, "failed to add distortion correction.");
- return;
+ return nullptr;
}
}
@@ -1591,30 +1727,236 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
uint8_t opcodeListBuf[listSize];
err = builder.buildOpList(opcodeListBuf);
if (err == OK) {
- BAIL_IF_INVALID(writer->addEntry(TAG_OPCODELIST3, listSize, opcodeListBuf,
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_OPCODELIST3, listSize, opcodeListBuf,
TIFF_IFD_0), env, TAG_OPCODELIST3, writer);
} else {
ALOGE("%s: Could not build list of opcodes for distortion correction and lens shading"
"map.", __FUNCTION__);
jniThrowRuntimeException(env, "failed to construct opcode list for distortion"
" correction and lens shading map");
- return;
+ return nullptr;
}
}
- DngCreator_setNativeContext(env, thiz, nativeContext);
+ {
+ // Set up orientation tags.
+ uint16_t orientation = nativeContext->getOrientation();
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_ORIENTATION, 1, &orientation, TIFF_IFD_0),
+ env, TAG_ORIENTATION, writer);
+
+ }
+
+ if (nativeContext->hasDescription()){
+ // Set Description
+ String8 description = nativeContext->getDescription();
+ size_t len = description.bytes() + 1;
+ if (writer->addEntry(TAG_IMAGEDESCRIPTION, len,
+ reinterpret_cast<const uint8_t*>(description.string()), TIFF_IFD_0) != OK) {
+ jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+ "Invalid metadata for tag %x", TAG_IMAGEDESCRIPTION);
+ }
+ }
+
+ if (nativeContext->hasGpsData()) {
+ // Set GPS tags
+ GpsData gpsData = nativeContext->getGpsData();
+ if (!writer->hasIfd(TIFF_IFD_GPSINFO)) {
+ if (writer->addSubIfd(TIFF_IFD_0, TIFF_IFD_GPSINFO, TiffWriter::GPSINFO) != OK) {
+ ALOGE("%s: Failed to add GpsInfo IFD %u to IFD %u", __FUNCTION__, TIFF_IFD_GPSINFO,
+ TIFF_IFD_0);
+ jniThrowException(env, "java/lang/IllegalStateException", "Failed to add GPSINFO");
+ return nullptr;
+ }
+ }
+
+ {
+ uint8_t version[] = {2, 3, 0, 0};
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSVERSIONID, 4, version,
+ TIFF_IFD_GPSINFO), env, TAG_GPSVERSIONID, writer);
+ }
+
+ {
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSLATITUDEREF,
+ GpsData::GPS_REF_LENGTH, gpsData.mLatitudeRef, TIFF_IFD_GPSINFO), env,
+ TAG_GPSLATITUDEREF, writer);
+ }
+
+ {
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSLONGITUDEREF,
+ GpsData::GPS_REF_LENGTH, gpsData.mLongitudeRef, TIFF_IFD_GPSINFO), env,
+ TAG_GPSLONGITUDEREF, writer);
+ }
+
+ {
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSLATITUDE, 3, gpsData.mLatitude,
+ TIFF_IFD_GPSINFO), env, TAG_GPSLATITUDE, writer);
+ }
+
+ {
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSLONGITUDE, 3, gpsData.mLongitude,
+ TIFF_IFD_GPSINFO), env, TAG_GPSLONGITUDE, writer);
+ }
+
+ {
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSTIMESTAMP, 3, gpsData.mTimestamp,
+ TIFF_IFD_GPSINFO), env, TAG_GPSTIMESTAMP, writer);
+ }
+
+ {
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSDATESTAMP,
+ GpsData::GPS_DATE_LENGTH, gpsData.mDate, TIFF_IFD_GPSINFO), env,
+ TAG_GPSDATESTAMP, writer);
+ }
+ }
+
+
+ if (nativeContext->hasThumbnail()) {
+ if (!writer->hasIfd(TIFF_IFD_SUB1)) {
+ if (writer->addSubIfd(TIFF_IFD_0, TIFF_IFD_SUB1) != OK) {
+ ALOGE("%s: Failed to add SubIFD %u to IFD %u", __FUNCTION__, TIFF_IFD_SUB1,
+ TIFF_IFD_0);
+ jniThrowException(env, "java/lang/IllegalStateException", "Failed to add SubIFD");
+ return nullptr;
+ }
+ }
+
+ Vector<uint16_t> tagsToMove;
+ tagsToMove.add(TAG_ORIENTATION);
+ tagsToMove.add(TAG_NEWSUBFILETYPE);
+ tagsToMove.add(TAG_ACTIVEAREA);
+ tagsToMove.add(TAG_BITSPERSAMPLE);
+ tagsToMove.add(TAG_COMPRESSION);
+ tagsToMove.add(TAG_IMAGEWIDTH);
+ tagsToMove.add(TAG_IMAGELENGTH);
+ tagsToMove.add(TAG_PHOTOMETRICINTERPRETATION);
+ tagsToMove.add(TAG_BLACKLEVEL);
+ tagsToMove.add(TAG_BLACKLEVELREPEATDIM);
+ tagsToMove.add(TAG_SAMPLESPERPIXEL);
+ tagsToMove.add(TAG_PLANARCONFIGURATION);
+ tagsToMove.add(TAG_CFAREPEATPATTERNDIM);
+ tagsToMove.add(TAG_CFAPATTERN);
+ tagsToMove.add(TAG_CFAPLANECOLOR);
+ tagsToMove.add(TAG_CFALAYOUT);
+ tagsToMove.add(TAG_XRESOLUTION);
+ tagsToMove.add(TAG_YRESOLUTION);
+ tagsToMove.add(TAG_RESOLUTIONUNIT);
+ tagsToMove.add(TAG_WHITELEVEL);
+ tagsToMove.add(TAG_DEFAULTSCALE);
+ tagsToMove.add(TAG_DEFAULTCROPORIGIN);
+ tagsToMove.add(TAG_DEFAULTCROPSIZE);
+ tagsToMove.add(TAG_OPCODELIST2);
+ tagsToMove.add(TAG_OPCODELIST3);
+
+ if (moveEntries(writer, TIFF_IFD_0, TIFF_IFD_SUB1, tagsToMove) != OK) {
+ jniThrowException(env, "java/lang/IllegalStateException", "Failed to move entries");
+ return nullptr;
+ }
+
+ // Make sure both IFDs get the same orientation tag
+ sp<TiffEntry> orientEntry = writer->getEntry(TAG_ORIENTATION, TIFF_IFD_SUB1);
+ if (orientEntry.get() != nullptr) {
+ writer->addEntry(orientEntry, TIFF_IFD_0);
+ }
+
+ // Setup thumbnail tags
+
+ {
+ // Set photometric interpretation
+ uint16_t interpretation = 2; // RGB
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_PHOTOMETRICINTERPRETATION, 1,
+ &interpretation, TIFF_IFD_0), env, TAG_PHOTOMETRICINTERPRETATION, writer);
+ }
+
+ {
+ // Set planar configuration
+ uint16_t config = 1; // Chunky
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_PLANARCONFIGURATION, 1, &config,
+ TIFF_IFD_0), env, TAG_PLANARCONFIGURATION, writer);
+ }
+
+ {
+ // Set samples per pixel
+ uint16_t samples = SAMPLES_PER_RGB_PIXEL;
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_SAMPLESPERPIXEL, 1, &samples,
+ TIFF_IFD_0), env, TAG_SAMPLESPERPIXEL, writer);
+ }
+
+ {
+ // Set bits per sample
+ uint16_t bits = BITS_PER_RGB_SAMPLE;
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_BITSPERSAMPLE, 1, &bits, TIFF_IFD_0),
+ env, TAG_BITSPERSAMPLE, writer);
+ }
+
+ {
+ // Set subfiletype
+ uint32_t subfileType = 1; // Thumbnail image
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_NEWSUBFILETYPE, 1, &subfileType,
+ TIFF_IFD_0), env, TAG_NEWSUBFILETYPE, writer);
+ }
+
+ {
+ // Set compression
+ uint16_t compression = 1; // None
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_COMPRESSION, 1, &compression,
+ TIFF_IFD_0), env, TAG_COMPRESSION, writer);
+ }
+
+ {
+ // Set dimensions
+ uint32_t uWidth = nativeContext->getThumbnailWidth();
+ uint32_t uHeight = nativeContext->getThumbnailHeight();
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_IMAGEWIDTH, 1, &uWidth, TIFF_IFD_0),
+ env, TAG_IMAGEWIDTH, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_IMAGELENGTH, 1, &uHeight, TIFF_IFD_0),
+ env, TAG_IMAGELENGTH, writer);
+ }
+
+ {
+ // x resolution
+ uint32_t xres[] = { 72, 1 }; // default 72 ppi
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_XRESOLUTION, 1, xres, TIFF_IFD_0),
+ env, TAG_XRESOLUTION, writer);
+
+ // y resolution
+ uint32_t yres[] = { 72, 1 }; // default 72 ppi
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_YRESOLUTION, 1, yres, TIFF_IFD_0),
+ env, TAG_YRESOLUTION, writer);
+
+ uint16_t unit = 2; // inches
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_RESOLUTIONUNIT, 1, &unit, TIFF_IFD_0),
+ env, TAG_RESOLUTIONUNIT, writer);
+ }
+ }
+
+ if (writer->addStrip(TIFF_IFD_0) != OK) {
+ ALOGE("%s: Could not setup thumbnail strip tags.", __FUNCTION__);
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Failed to setup thumbnail strip tags.");
+ return nullptr;
+ }
+
+ if (writer->hasIfd(TIFF_IFD_SUB1)) {
+ if (writer->addStrip(TIFF_IFD_SUB1) != OK) {
+ ALOGE("%s: Could not main image strip tags.", __FUNCTION__);
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Failed to setup main image strip tags.");
+ return nullptr;
+ }
+ }
+ return writer;
}
static void DngCreator_destroy(JNIEnv* env, jobject thiz) {
ALOGV("%s:", __FUNCTION__);
- DngCreator_setNativeContext(env, thiz, NULL);
+ DngCreator_setNativeContext(env, thiz, nullptr);
}
static void DngCreator_nativeSetOrientation(JNIEnv* env, jobject thiz, jint orient) {
ALOGV("%s:", __FUNCTION__);
- TiffWriter* writer = DngCreator_getCreator(env, thiz);
- if (writer == NULL) {
+ NativeContext* context = DngCreator_getNativeContext(env, thiz);
+ if (context == nullptr) {
ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__);
jniThrowException(env, "java/lang/AssertionError",
"setOrientation called with uninitialized DngCreator");
@@ -1622,138 +1964,73 @@ static void DngCreator_nativeSetOrientation(JNIEnv* env, jobject thiz, jint orie
}
uint16_t orientation = static_cast<uint16_t>(orient);
- BAIL_IF_INVALID(writer->addEntry(TAG_ORIENTATION, 1, &orientation, TIFF_IFD_0), env,
- TAG_ORIENTATION, writer);
-
- // Set main image orientation also if in a separate IFD
- if (writer->hasIfd(TIFF_IFD_SUB1)) {
- BAIL_IF_INVALID(writer->addEntry(TAG_ORIENTATION, 1, &orientation, TIFF_IFD_SUB1), env,
- TAG_ORIENTATION, writer);
- }
+ context->setOrientation(orientation);
}
static void DngCreator_nativeSetDescription(JNIEnv* env, jobject thiz, jstring description) {
ALOGV("%s:", __FUNCTION__);
- TiffWriter* writer = DngCreator_getCreator(env, thiz);
- if (writer == NULL) {
+ NativeContext* context = DngCreator_getNativeContext(env, thiz);
+ if (context == nullptr) {
ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__);
jniThrowException(env, "java/lang/AssertionError",
"setDescription called with uninitialized DngCreator");
return;
}
- const char* desc = env->GetStringUTFChars(description, NULL);
- size_t len = strlen(desc) + 1;
-
- if (writer->addEntry(TAG_IMAGEDESCRIPTION, len,
- reinterpret_cast<const uint8_t*>(desc), TIFF_IFD_0) != OK) {
- jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
- "Invalid metadata for tag %x", TAG_IMAGEDESCRIPTION);
- }
-
+ const char* desc = env->GetStringUTFChars(description, nullptr);
+ context->setDescription(String8(desc));
env->ReleaseStringUTFChars(description, desc);
}
-static void DngCreator_nativeSetGpsTags(JNIEnv* env, jobject thiz, jintArray latTag, jstring latRef,
- jintArray longTag, jstring longRef, jstring dateTag, jintArray timeTag) {
+static void DngCreator_nativeSetGpsTags(JNIEnv* env, jobject thiz, jintArray latTag,
+ jstring latRef, jintArray longTag, jstring longRef, jstring dateTag, jintArray timeTag) {
ALOGV("%s:", __FUNCTION__);
- TiffWriter* writer = DngCreator_getCreator(env, thiz);
- if (writer == NULL) {
+ NativeContext* context = DngCreator_getNativeContext(env, thiz);
+ if (context == nullptr) {
ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__);
jniThrowException(env, "java/lang/AssertionError",
"setGpsTags called with uninitialized DngCreator");
return;
}
- if (!writer->hasIfd(TIFF_IFD_GPSINFO)) {
- if (writer->addSubIfd(TIFF_IFD_0, TIFF_IFD_GPSINFO, TiffWriter::GPSINFO) != OK) {
- ALOGE("%s: Failed to add GpsInfo IFD %u to IFD %u", __FUNCTION__, TIFF_IFD_GPSINFO,
- TIFF_IFD_0);
- jniThrowException(env, "java/lang/IllegalStateException", "Failed to add GPSINFO");
- return;
- }
- }
+ GpsData data;
- const jsize GPS_VALUE_LENGTH = 6;
jsize latLen = env->GetArrayLength(latTag);
jsize longLen = env->GetArrayLength(longTag);
jsize timeLen = env->GetArrayLength(timeTag);
- if (latLen != GPS_VALUE_LENGTH) {
+ if (latLen != GpsData::GPS_VALUE_LENGTH) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"invalid latitude tag length");
return;
- } else if (longLen != GPS_VALUE_LENGTH) {
+ } else if (longLen != GpsData::GPS_VALUE_LENGTH) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"invalid longitude tag length");
return;
- } else if (timeLen != GPS_VALUE_LENGTH) {
+ } else if (timeLen != GpsData::GPS_VALUE_LENGTH) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"invalid time tag length");
return;
}
- uint32_t latitude[GPS_VALUE_LENGTH];
- uint32_t longitude[GPS_VALUE_LENGTH];
- uint32_t timestamp[GPS_VALUE_LENGTH];
-
- env->GetIntArrayRegion(latTag, 0, static_cast<jsize>(GPS_VALUE_LENGTH),
- reinterpret_cast<jint*>(&latitude));
- env->GetIntArrayRegion(longTag, 0, static_cast<jsize>(GPS_VALUE_LENGTH),
- reinterpret_cast<jint*>(&longitude));
- env->GetIntArrayRegion(timeTag, 0, static_cast<jsize>(GPS_VALUE_LENGTH),
- reinterpret_cast<jint*>(&timestamp));
-
- const jsize GPS_REF_LENGTH = 2;
- const jsize GPS_DATE_LENGTH = 11;
- uint8_t latitudeRef[GPS_REF_LENGTH];
- uint8_t longitudeRef[GPS_REF_LENGTH];
- uint8_t date[GPS_DATE_LENGTH];
-
- env->GetStringUTFRegion(latRef, 0, 1, reinterpret_cast<char*>(&latitudeRef));
- latitudeRef[GPS_REF_LENGTH - 1] = '\0';
- env->GetStringUTFRegion(longRef, 0, 1, reinterpret_cast<char*>(&longitudeRef));
- longitudeRef[GPS_REF_LENGTH - 1] = '\0';
-
- env->GetStringUTFRegion(dateTag, 0, GPS_DATE_LENGTH - 1, reinterpret_cast<char*>(&date));
- date[GPS_DATE_LENGTH - 1] = '\0';
-
- {
- uint8_t version[] = {2, 3, 0, 0};
- BAIL_IF_INVALID(writer->addEntry(TAG_GPSVERSIONID, 4, version,
- TIFF_IFD_GPSINFO), env, TAG_GPSVERSIONID, writer);
- }
-
- {
- BAIL_IF_INVALID(writer->addEntry(TAG_GPSLATITUDEREF, GPS_REF_LENGTH, latitudeRef,
- TIFF_IFD_GPSINFO), env, TAG_GPSLATITUDEREF, writer);
- }
-
- {
- BAIL_IF_INVALID(writer->addEntry(TAG_GPSLONGITUDEREF, GPS_REF_LENGTH, longitudeRef,
- TIFF_IFD_GPSINFO), env, TAG_GPSLONGITUDEREF, writer);
- }
-
- {
- BAIL_IF_INVALID(writer->addEntry(TAG_GPSLATITUDE, 3, latitude,
- TIFF_IFD_GPSINFO), env, TAG_GPSLATITUDE, writer);
- }
+ env->GetIntArrayRegion(latTag, 0, static_cast<jsize>(GpsData::GPS_VALUE_LENGTH),
+ reinterpret_cast<jint*>(&data.mLatitude));
+ env->GetIntArrayRegion(longTag, 0, static_cast<jsize>(GpsData::GPS_VALUE_LENGTH),
+ reinterpret_cast<jint*>(&data.mLongitude));
+ env->GetIntArrayRegion(timeTag, 0, static_cast<jsize>(GpsData::GPS_VALUE_LENGTH),
+ reinterpret_cast<jint*>(&data.mTimestamp));
- {
- BAIL_IF_INVALID(writer->addEntry(TAG_GPSLONGITUDE, 3, longitude,
- TIFF_IFD_GPSINFO), env, TAG_GPSLONGITUDE, writer);
- }
- {
- BAIL_IF_INVALID(writer->addEntry(TAG_GPSTIMESTAMP, 3, timestamp,
- TIFF_IFD_GPSINFO), env, TAG_GPSTIMESTAMP, writer);
- }
+ env->GetStringUTFRegion(latRef, 0, 1, reinterpret_cast<char*>(&data.mLatitudeRef));
+ data.mLatitudeRef[GpsData::GPS_REF_LENGTH - 1] = '\0';
+ env->GetStringUTFRegion(longRef, 0, 1, reinterpret_cast<char*>(&data.mLongitudeRef));
+ data.mLongitudeRef[GpsData::GPS_REF_LENGTH - 1] = '\0';
+ env->GetStringUTFRegion(dateTag, 0, GpsData::GPS_DATE_LENGTH - 1,
+ reinterpret_cast<char*>(&data.mDate));
+ data.mDate[GpsData::GPS_DATE_LENGTH - 1] = '\0';
- {
- BAIL_IF_INVALID(writer->addEntry(TAG_GPSDATESTAMP, GPS_DATE_LENGTH, date,
- TIFF_IFD_GPSINFO), env, TAG_GPSDATESTAMP, writer);
- }
+ context->setGpsData(data);
}
static void DngCreator_nativeSetThumbnail(JNIEnv* env, jobject thiz, jobject buffer, jint width,
@@ -1761,8 +2038,7 @@ static void DngCreator_nativeSetThumbnail(JNIEnv* env, jobject thiz, jobject buf
ALOGV("%s:", __FUNCTION__);
NativeContext* context = DngCreator_getNativeContext(env, thiz);
- TiffWriter* writer = DngCreator_getCreator(env, thiz);
- if (writer == NULL || context == NULL) {
+ if (context == nullptr) {
ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__);
jniThrowException(env, "java/lang/AssertionError",
"setThumbnail called with uninitialized DngCreator");
@@ -1779,147 +2055,12 @@ static void DngCreator_nativeSetThumbnail(JNIEnv* env, jobject thiz, jobject buf
}
uint8_t* pixelBytes = reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(buffer));
- if (pixelBytes == NULL) {
+ if (pixelBytes == nullptr) {
ALOGE("%s: Could not get native ByteBuffer", __FUNCTION__);
jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid ByteBuffer");
return;
}
- if (!writer->hasIfd(TIFF_IFD_SUB1)) {
- if (writer->addSubIfd(TIFF_IFD_0, TIFF_IFD_SUB1) != OK) {
- ALOGE("%s: Failed to add SubIFD %u to IFD %u", __FUNCTION__, TIFF_IFD_SUB1,
- TIFF_IFD_0);
- jniThrowException(env, "java/lang/IllegalStateException", "Failed to add SubIFD");
- return;
- }
-
- Vector<uint16_t> tagsToMove;
- tagsToMove.add(TAG_ORIENTATION);
- tagsToMove.add(TAG_NEWSUBFILETYPE);
- tagsToMove.add(TAG_BITSPERSAMPLE);
- tagsToMove.add(TAG_COMPRESSION);
- tagsToMove.add(TAG_IMAGEWIDTH);
- tagsToMove.add(TAG_IMAGELENGTH);
- tagsToMove.add(TAG_PHOTOMETRICINTERPRETATION);
- tagsToMove.add(TAG_BLACKLEVEL);
- tagsToMove.add(TAG_BLACKLEVELREPEATDIM);
- tagsToMove.add(TAG_SAMPLESPERPIXEL);
- tagsToMove.add(TAG_PLANARCONFIGURATION);
- tagsToMove.add(TAG_CFAREPEATPATTERNDIM);
- tagsToMove.add(TAG_CFAPATTERN);
- tagsToMove.add(TAG_CFAPLANECOLOR);
- tagsToMove.add(TAG_CFALAYOUT);
- tagsToMove.add(TAG_XRESOLUTION);
- tagsToMove.add(TAG_YRESOLUTION);
- tagsToMove.add(TAG_RESOLUTIONUNIT);
- tagsToMove.add(TAG_WHITELEVEL);
- tagsToMove.add(TAG_DEFAULTSCALE);
- tagsToMove.add(TAG_ROWSPERSTRIP);
- tagsToMove.add(TAG_STRIPBYTECOUNTS);
- tagsToMove.add(TAG_STRIPOFFSETS);
- tagsToMove.add(TAG_DEFAULTCROPORIGIN);
- tagsToMove.add(TAG_DEFAULTCROPSIZE);
- tagsToMove.add(TAG_OPCODELIST2);
- tagsToMove.add(TAG_OPCODELIST3);
-
- if (moveEntries(writer, TIFF_IFD_0, TIFF_IFD_SUB1, tagsToMove) != OK) {
- jniThrowException(env, "java/lang/IllegalStateException", "Failed to move entries");
- return;
- }
-
- // Make sure both IFDs get the same orientation tag
- sp<TiffEntry> orientEntry = writer->getEntry(TAG_ORIENTATION, TIFF_IFD_SUB1);
- if (orientEntry != NULL) {
- writer->addEntry(orientEntry, TIFF_IFD_0);
- }
- }
-
- // Setup thumbnail tags
-
- {
- // Set photometric interpretation
- uint16_t interpretation = 2; // RGB
- BAIL_IF_INVALID(writer->addEntry(TAG_PHOTOMETRICINTERPRETATION, 1, &interpretation,
- TIFF_IFD_0), env, TAG_PHOTOMETRICINTERPRETATION, writer);
- }
-
- {
- // Set planar configuration
- uint16_t config = 1; // Chunky
- BAIL_IF_INVALID(writer->addEntry(TAG_PLANARCONFIGURATION, 1, &config, TIFF_IFD_0),
- env, TAG_PLANARCONFIGURATION, writer);
- }
-
- {
- // Set samples per pixel
- uint16_t samples = SAMPLES_PER_RGB_PIXEL;
- BAIL_IF_INVALID(writer->addEntry(TAG_SAMPLESPERPIXEL, 1, &samples, TIFF_IFD_0),
- env, TAG_SAMPLESPERPIXEL, writer);
- }
-
- {
- // Set bits per sample
- uint16_t bits = BITS_PER_RGB_SAMPLE;
- BAIL_IF_INVALID(writer->addEntry(TAG_BITSPERSAMPLE, 1, &bits, TIFF_IFD_0), env,
- TAG_BITSPERSAMPLE, writer);
- }
-
- {
- // Set subfiletype
- uint32_t subfileType = 1; // Thumbnail image
- BAIL_IF_INVALID(writer->addEntry(TAG_NEWSUBFILETYPE, 1, &subfileType, TIFF_IFD_0), env,
- TAG_NEWSUBFILETYPE, writer);
- }
-
- {
- // Set compression
- uint16_t compression = 1; // None
- BAIL_IF_INVALID(writer->addEntry(TAG_COMPRESSION, 1, &compression, TIFF_IFD_0), env,
- TAG_COMPRESSION, writer);
- }
-
- {
- // Set dimensions
- uint32_t uWidth = static_cast<uint32_t>(width);
- uint32_t uHeight = static_cast<uint32_t>(height);
- BAIL_IF_INVALID(writer->addEntry(TAG_IMAGEWIDTH, 1, &uWidth, TIFF_IFD_0), env,
- TAG_IMAGEWIDTH, writer);
- BAIL_IF_INVALID(writer->addEntry(TAG_IMAGELENGTH, 1, &uHeight, TIFF_IFD_0), env,
- TAG_IMAGELENGTH, writer);
- }
-
- {
- // x resolution
- uint32_t xres[] = { 72, 1 }; // default 72 ppi
- BAIL_IF_INVALID(writer->addEntry(TAG_XRESOLUTION, 1, xres, TIFF_IFD_0),
- env, TAG_XRESOLUTION, writer);
-
- // y resolution
- uint32_t yres[] = { 72, 1 }; // default 72 ppi
- BAIL_IF_INVALID(writer->addEntry(TAG_YRESOLUTION, 1, yres, TIFF_IFD_0),
- env, TAG_YRESOLUTION, writer);
-
- uint16_t unit = 2; // inches
- BAIL_IF_INVALID(writer->addEntry(TAG_RESOLUTIONUNIT, 1, &unit, TIFF_IFD_0),
- env, TAG_RESOLUTIONUNIT, writer);
- }
-
- {
- // Setup data strips
- if (writer->addStrip(TIFF_IFD_0) != OK) {
- ALOGE("%s: Could not setup thumbnail strip tags.", __FUNCTION__);
- jniThrowException(env, "java/lang/IllegalStateException",
- "Failed to setup thumbnail strip tags.");
- return;
- }
- if (writer->addStrip(TIFF_IFD_SUB1) != OK) {
- ALOGE("%s: Could not main image strip tags.", __FUNCTION__);
- jniThrowException(env, "java/lang/IllegalStateException",
- "Failed to setup main image strip tags.");
- return;
- }
- }
-
if (!context->setThumbnail(pixelBytes, width, height)) {
jniThrowException(env, "java/lang/IllegalStateException",
"Failed to set thumbnail.");
@@ -1947,16 +2088,20 @@ static void DngCreator_nativeWriteImage(JNIEnv* env, jobject thiz, jobject outSt
return;
}
- TiffWriter* writer = DngCreator_getCreator(env, thiz);
NativeContext* context = DngCreator_getNativeContext(env, thiz);
- if (writer == NULL || context == NULL) {
+ if (context == nullptr) {
ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__);
jniThrowException(env, "java/lang/AssertionError",
"Write called with uninitialized DngCreator");
return;
}
+ sp<TiffWriter> writer = DngCreator_setup(env, thiz, uWidth, uHeight);
- // Validate DNG header
+ if (writer.get() == nullptr) {
+ return;
+ }
+
+ // Validate DNG size
if (!validateDngHeader(env, writer, *(context->getCharacteristics()), width, height)) {
return;
}
@@ -1991,7 +2136,7 @@ static void DngCreator_nativeWriteImage(JNIEnv* env, jobject thiz, jobject outSt
}
uint8_t* pixelBytes = reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(inBuffer));
- if (pixelBytes == NULL) {
+ if (pixelBytes == nullptr) {
ALOGE("%s: Could not get native ByteBuffer", __FUNCTION__);
jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid ByteBuffer");
return;
@@ -2051,16 +2196,20 @@ static void DngCreator_nativeWriteInputStream(JNIEnv* env, jobject thiz, jobject
return;
}
- TiffWriter* writer = DngCreator_getCreator(env, thiz);
NativeContext* context = DngCreator_getNativeContext(env, thiz);
- if (writer == NULL || context == NULL) {
+ if (context == nullptr) {
ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__);
jniThrowException(env, "java/lang/AssertionError",
"Write called with uninitialized DngCreator");
return;
}
+ sp<TiffWriter> writer = DngCreator_setup(env, thiz, uWidth, uHeight);
+
+ if (writer.get() == nullptr) {
+ return;
+ }
- // Validate DNG header
+ // Validate DNG size
if (!validateDngHeader(env, writer, *(context->getCharacteristics()), width, height)) {
return;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 92862f5..3e22e09 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1749,6 +1749,10 @@
<!-- ==================================== -->
<eat-comment />
+ <!-- @SystemApi Allows access to the list of accounts in the Accounts Service. -->
+ <permission android:name="android.permission.GET_ACCOUNTS_PRIVILEGED"
+ android:protectionLevel="signature|privileged" />
+
<!-- @SystemApi Allows applications to RW to diagnostic resources.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.DIAGNOSTIC"
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index be2b962..0533317 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1001,7 +1001,7 @@
<string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Puedes cambiar esta opción más tarde en Ajustes &gt; Aplicaciones."</string>
<string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"Permitir siempre"</string>
<string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"No permitir nunca"</string>
- <string name="sim_removed_title" msgid="6227712319223226185">"Tarjeta SIM eliminada"</string>
+ <string name="sim_removed_title" msgid="6227712319223226185">"Tarjeta SIM retirada"</string>
<string name="sim_removed_message" msgid="5450336489923274918">"La red móvil no estará disponible hasta que reinicies el dispositivo con una tarjeta SIM válida insertada."</string>
<string name="sim_done_button" msgid="827949989369963775">"Listo"</string>
<string name="sim_added_title" msgid="3719670512889674693">"Tarjeta SIM añadida"</string>
diff --git a/core/res/res/values-mcc310-mnc260-pt-rBR/strings.xml b/core/res/res/values-mcc310-mnc260-pt-rBR/strings.xml
new file mode 100644
index 0000000..bad49c3
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc260-pt-rBR/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string-array name="wfcOperatorErrorAlertMessages">
+ <item msgid="7239039348648848288">"Para fazer chamadas e enviar mensagens por Wi-Fi, primeiro peça à sua operadora para configurar esse serviço. Depois ative novamente as chamadas por Wi-Fi nas configurações."</item>
+ </string-array>
+ <string-array name="wfcOperatorErrorNotificationMessages">
+ <item msgid="483847327467331298">"Faça registro na sua operadora"</item>
+ </string-array>
+ <string name="wfcSpnFormat" msgid="4982938551498609442">"%s chamada Wi-Fi"</string>
+</resources>
diff --git a/core/res/res/values-mcc425/config.xml b/core/res/res/values-mcc425/config.xml
new file mode 100644
index 0000000..95d30a4
--- /dev/null
+++ b/core/res/res/values-mcc425/config.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+ <bool name="config_use_sim_language_file">false</bool>
+</resources>
diff --git a/core/res/res/values-mcc432/config.xml b/core/res/res/values-mcc432/config.xml
new file mode 100644
index 0000000..95d30a4
--- /dev/null
+++ b/core/res/res/values-mcc432/config.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+ <bool name="config_use_sim_language_file">false</bool>
+</resources>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index be72354..df9f2805 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -1042,7 +1042,7 @@
<string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB төхөөрөмжид холбогдов"</string>
<string name="usb_notification_message" msgid="7347368030849048437">"Нэмэлт сонголтыг харахын тулд дарна."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB дебаг холбогдсон"</string>
- <string name="adb_active_notification_message" msgid="1016654627626476142">"USB дебаг хийхийг идэвхгүй болгох бол хүрнэ үү."</string>
+ <string name="adb_active_notification_message" msgid="1016654627626476142">"USB дебагийг идэвхгүй болгох бол хүрнэ үү."</string>
<string name="select_input_method" msgid="8547250819326693584">"Гарыг өөрчлөх"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Гар сонгох"</string>
<string name="show_ime" msgid="9157568568695230830">"Оруулах аргыг харуулах"</string>
diff --git a/core/res/res/values-pt-rBR-watch/strings.xml b/core/res/res/values-pt-rBR-watch/strings.xml
new file mode 100644
index 0000000..120e4a5
--- /dev/null
+++ b/core/res/res/values-pt-rBR-watch/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="android_upgrading_apk" msgid="1090732262010398759">"App <xliff:g id="NUMBER_0">%1$d</xliff:g> de <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+</resources>
diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml
index 549c5ef7..2bde626 100644
--- a/core/res/res/values-sq-rAL/strings.xml
+++ b/core/res/res/values-sq-rAL/strings.xml
@@ -21,7 +21,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"kilobajt"</string>
+ <string name="kilobyteShort" msgid="5973789783504771878">"KB"</string>
<string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
<string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
<string name="terabyteShort" msgid="231613018159186962">"terabajt"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 06b6389..54848e9 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -408,6 +408,7 @@
<integer translatable="false" name="config_wifi_framework_wifi_score_good_link_speed_24">24</integer>
<integer translatable="false" name="config_wifi_framework_wifi_score_good_link_speed_5">36</integer>
<string translatable="false" name="config_wifi_random_mac_oui">DA-A1-19</string>
+ <string translatable="false" name="config_wifi_framework_sap_2G_channel_list">1,6,11</string>
<bool translatable="false" name="config_wifi_framework_cellular_handover_enable_user_triggered_adjustment">true</bool>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 568e61e..85b6c12 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2652,4 +2652,6 @@
<public type="id" name="accessibilityActionScrollDown" id="0x0102003a" />
<public type="id" name="accessibilityActionScrollRight" id="0x0102003b" />
<public type="id" name="accessibilityActionContextClick" id="0x0102003c" />
+
+ <public type="string" name="fingerprint_icon_content_description" />
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 35c1f0e..a45a0fa 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1221,6 +1221,9 @@
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- Content description which should be used for the fingerprint icon. -->
+ <string name="fingerprint_icon_content_description">Fingerprint icon</string>
+
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_readSyncSettings">read sync settings</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index fe82b8c..8070986 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -337,6 +337,7 @@
<java-symbol type="integer" name="config_wifi_active_rx_cur_ma" />
<java-symbol type="integer" name="config_wifi_tx_cur_ma" />
<java-symbol type="integer" name="config_wifi_operating_voltage_mv" />
+ <java-symbol type="string" name="config_wifi_framework_sap_2G_channel_list" />
<java-symbol type="bool" name="editable_voicemailnumber" />