Merge "Un-remove legacy ConnectivityManager API." into mnc-dev
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index cfd5bf1..c4de4a2 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -662,6 +662,17 @@
}
/**
+ * Returns true if this link or any of its stacked interfaces has an IPv4 address.
+ *
+ * @return {@code true} if there is an IPv4 address, {@code false} otherwise.
+ */
+ private boolean hasIPv4AddressOnInterface(String iface) {
+ return (mIfaceName.equals(iface) && hasIPv4Address()) ||
+ (iface != null && mStackedLinks.containsKey(iface) &&
+ mStackedLinks.get(iface).hasIPv4Address());
+ }
+
+ /**
* Returns true if this link has a global preferred IPv6 address.
*
* @return {@code true} if there is a global preferred IPv6 address, {@code false} otherwise.
@@ -792,7 +803,7 @@
if (ip instanceof Inet4Address) {
// For IPv4, it suffices for now to simply have any address.
- return hasIPv4Address();
+ return hasIPv4AddressOnInterface(bestRoute.getInterface());
} else if (ip instanceof Inet6Address) {
if (ip.isLinkLocalAddress()) {
// For now, just make sure link-local destinations have
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 @@
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/widget/Editor.java b/core/java/android/widget/Editor.java
index e169ceb..010cb27 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -4060,9 +4060,17 @@
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
@@ -4100,7 +4108,7 @@
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;
}
@@ -4142,12 +4150,12 @@
// 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;
@@ -4160,6 +4168,21 @@
}
}
+ 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) {
@@ -4215,17 +4238,22 @@
}
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);
@@ -4243,6 +4271,20 @@
}
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 {
@@ -4254,9 +4296,17 @@
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
@@ -4294,7 +4344,7 @@
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;
}
@@ -4336,12 +4386,12 @@
// 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;
@@ -4354,6 +4404,21 @@
}
}
+ 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) {
@@ -4409,17 +4474,22 @@
}
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);
@@ -4437,6 +4507,20 @@
}
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/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 @@
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 @@
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 @@
*/
class NativeContext : public LightRefBase<NativeContext> {
-
public:
+ enum {
+ DATETIME_COUNT = 20,
+ };
+
NativeContext(const CameraMetadata& characteristics, const CameraMetadata& result);
virtual ~NativeContext();
@@ -119,12 +152,28 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// ----------------------------------------------------------------------------
/**
- * 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.
+ // 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;
- uint32_t bLeft = bufXMin + margin;
- uint32_t bTop = bufYMin + margin;
- uint32_t bRight = bufXMin + bufWidth - margin;
- uint32_t bBottom = bufYMin + 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 @@
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 @@
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 @@
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 @@
ALOGV("%s:", __FUNCTION__);
NativeContext* current = DngCreator_getNativeContext(env, thiz);
- if (context != NULL) {
+ if (context != nullptr) {
context->incStrong((void*) DngCreator_setNativeContext);
}
@@ -893,15 +1001,6 @@
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 @@
}
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 @@
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 @@
{
// 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 @@
"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 @@
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 @@
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 @@
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);
+ String8 captureTime = nativeContext->getCaptureTime();
- size_t len = strlen(captureTime) + 1;
- if (len != DATETIME_COUNT) {
- jniThrowException(env, "java/lang/IllegalArgumentException",
- "Timestamp string length is not required 20 characters");
- return;
- }
-
- 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, ©right,
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_COPYRIGHT, 1, ©right,
TIFF_IFD_0), env, TAG_COPYRIGHT, writer);
}
@@ -1181,7 +1315,7 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
}
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 @@
// 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 @@
// 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 @@
// 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 @@
}
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 @@
// 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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
// 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_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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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,211 +1727,103 @@
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);
-static void DngCreator_destroy(JNIEnv* env, jobject thiz) {
- ALOGV("%s:", __FUNCTION__);
- DngCreator_setNativeContext(env, thiz, NULL);
-}
-
-static void DngCreator_nativeSetOrientation(JNIEnv* env, jobject thiz, jint orient) {
- ALOGV("%s:", __FUNCTION__);
-
- TiffWriter* writer = DngCreator_getCreator(env, thiz);
- if (writer == NULL) {
- ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__);
- jniThrowException(env, "java/lang/AssertionError",
- "setOrientation called with uninitialized DngCreator");
- return;
}
- 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);
- }
-}
-
-static void DngCreator_nativeSetDescription(JNIEnv* env, jobject thiz, jstring description) {
- ALOGV("%s:", __FUNCTION__);
-
- TiffWriter* writer = DngCreator_getCreator(env, thiz);
- if (writer == NULL) {
- 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);
- }
-
- env->ReleaseStringUTFChars(description, desc);
-}
-
-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) {
- 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;
+ 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);
}
}
- 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) {
- jniThrowException(env, "java/lang/IllegalArgumentException",
- "invalid latitude tag length");
- return;
- } else if (longLen != GPS_VALUE_LENGTH) {
- jniThrowException(env, "java/lang/IllegalArgumentException",
- "invalid longitude tag length");
- return;
- } else if (timeLen != GPS_VALUE_LENGTH) {
- jniThrowException(env, "java/lang/IllegalArgumentException",
- "invalid time tag length");
- return;
+ 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);
+ }
}
- 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*>(×tamp));
-
- 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);
- }
-
- {
- 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);
- }
-
- {
- BAIL_IF_INVALID(writer->addEntry(TAG_GPSDATESTAMP, GPS_DATE_LENGTH, date,
- TIFF_IFD_GPSINFO), env, TAG_GPSDATESTAMP, writer);
- }
-}
-
-static void DngCreator_nativeSetThumbnail(JNIEnv* env, jobject thiz, jobject buffer, jint width,
- jint height) {
- ALOGV("%s:", __FUNCTION__);
-
- NativeContext* context = DngCreator_getNativeContext(env, thiz);
- TiffWriter* writer = DngCreator_getCreator(env, thiz);
- if (writer == NULL || context == NULL) {
- ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__);
- jniThrowException(env, "java/lang/AssertionError",
- "setThumbnail called with uninitialized DngCreator");
- return;
- }
-
- size_t fullSize = width * height * BYTES_PER_RGB_PIXEL;
- jlong capacity = env->GetDirectBufferCapacity(buffer);
- if (static_cast<uint64_t>(capacity) != static_cast<uint64_t>(fullSize)) {
- jniThrowExceptionFmt(env, "java/lang/AssertionError",
- "Invalid size %d for thumbnail, expected size was %d",
- capacity, fullSize);
- return;
- }
-
- uint8_t* pixelBytes = reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(buffer));
- if (pixelBytes == NULL) {
- 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;
+ 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);
@@ -1814,9 +1842,6 @@
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);
@@ -1824,101 +1849,217 @@
if (moveEntries(writer, TIFF_IFD_0, TIFF_IFD_SUB1, tagsToMove) != OK) {
jniThrowException(env, "java/lang/IllegalStateException", "Failed to move entries");
- return;
+ return nullptr;
}
// Make sure both IFDs get the same orientation tag
sp<TiffEntry> orientEntry = writer->getEntry(TAG_ORIENTATION, TIFF_IFD_SUB1);
- if (orientEntry != NULL) {
+ if (orientEntry.get() != nullptr) {
writer->addEntry(orientEntry, TIFF_IFD_0);
}
- }
- // Setup thumbnail tags
+ // 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;
+ {
+ // 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;
+ return nullptr;
}
}
+ return writer;
+}
+
+static void DngCreator_destroy(JNIEnv* env, jobject thiz) {
+ ALOGV("%s:", __FUNCTION__);
+ DngCreator_setNativeContext(env, thiz, nullptr);
+}
+
+static void DngCreator_nativeSetOrientation(JNIEnv* env, jobject thiz, jint orient) {
+ ALOGV("%s:", __FUNCTION__);
+
+ 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");
+ return;
+ }
+
+ uint16_t orientation = static_cast<uint16_t>(orient);
+ context->setOrientation(orientation);
+}
+
+static void DngCreator_nativeSetDescription(JNIEnv* env, jobject thiz, jstring description) {
+ ALOGV("%s:", __FUNCTION__);
+
+ 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, 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) {
+ ALOGV("%s:", __FUNCTION__);
+
+ 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;
+ }
+
+ GpsData data;
+
+ jsize latLen = env->GetArrayLength(latTag);
+ jsize longLen = env->GetArrayLength(longTag);
+ jsize timeLen = env->GetArrayLength(timeTag);
+ if (latLen != GpsData::GPS_VALUE_LENGTH) {
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "invalid latitude tag length");
+ return;
+ } else if (longLen != GpsData::GPS_VALUE_LENGTH) {
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "invalid longitude tag length");
+ return;
+ } else if (timeLen != GpsData::GPS_VALUE_LENGTH) {
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "invalid time tag length");
+ return;
+ }
+
+ 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));
+
+
+ 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';
+
+ context->setGpsData(data);
+}
+
+static void DngCreator_nativeSetThumbnail(JNIEnv* env, jobject thiz, jobject buffer, jint width,
+ jint height) {
+ ALOGV("%s:", __FUNCTION__);
+
+ NativeContext* context = DngCreator_getNativeContext(env, thiz);
+ if (context == nullptr) {
+ ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__);
+ jniThrowException(env, "java/lang/AssertionError",
+ "setThumbnail called with uninitialized DngCreator");
+ return;
+ }
+
+ size_t fullSize = width * height * BYTES_PER_RGB_PIXEL;
+ jlong capacity = env->GetDirectBufferCapacity(buffer);
+ if (static_cast<uint64_t>(capacity) != static_cast<uint64_t>(fullSize)) {
+ jniThrowExceptionFmt(env, "java/lang/AssertionError",
+ "Invalid size %d for thumbnail, expected size was %d",
+ capacity, fullSize);
+ return;
+ }
+
+ uint8_t* pixelBytes = reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(buffer));
+ if (pixelBytes == nullptr) {
+ ALOGE("%s: Could not get native ByteBuffer", __FUNCTION__);
+ jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid ByteBuffer");
+ return;
+ }
if (!context->setThumbnail(pixelBytes, width, height)) {
jniThrowException(env, "java/lang/IllegalStateException",
@@ -1947,16 +2088,20 @@
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 @@
}
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 @@
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;
}
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index a95db9f..62aabb1 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -6758,7 +6758,13 @@
printf(" NON-INTEGER ResTable_type ADDRESS: %p\n", type);
continue;
}
- String8 configStr = type->config.toString();
+
+ // Always copy the config, as fields get added and we need to
+ // set the defaults.
+ ResTable_config thisConfig;
+ thisConfig.copyFromDtoH(type->config);
+
+ String8 configStr = thisConfig.toString();
printf(" config %s:\n", configStr.size() > 0
? configStr.string() : "(default)");
size_t entryCount = dtohl(type->entryCount);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index fb940d2..dfce170 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -3163,9 +3163,7 @@
@Override
public boolean shouldDisableNavbarGestures() {
- return !isDeviceProvisioned()
- || mExpandedVisible
- || (mDisabled1 & StatusBarManager.DISABLE_SEARCH) != 0;
+ return !isDeviceProvisioned() || (mDisabled1 & StatusBarManager.DISABLE_SEARCH) != 0;
}
public void postStartActivityDismissingKeyguard(final Intent intent, int delay) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 82224d4..13e9b16 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -25,6 +25,7 @@
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
@@ -389,7 +390,7 @@
}
// Fill in the network name if we think we have it.
if (mCurrentState.networkName == mNetworkNameDefault && mServiceState != null
- && mServiceState.getOperatorAlphaShort() != null) {
+ && !TextUtils.isEmpty(mServiceState.getOperatorAlphaShort())) {
mCurrentState.networkName = mServiceState.getOperatorAlphaShort();
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index eb74ab0..76d2258 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1772,7 +1772,7 @@
// Start gathering diagnostic information.
netDiags.add(new NetworkDiagnostics(
nai.network,
- new LinkProperties(nai.linkProperties),
+ new LinkProperties(nai.linkProperties), // Must be a copy.
DIAG_TIME_MS));
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 447fe87..d0f68f0 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -1261,9 +1261,11 @@
Slog.v(TAG, "WiFi energy data was reset, new WiFi energy data is " + result);
}
+ // There is some accuracy error in reports so allow 30 milliseconds of error.
+ final long SAMPLE_ERROR_MILLIS = 30;
final long totalTimeMs = result.mControllerIdleTimeMs + result.mControllerRxTimeMs +
result.mControllerTxTimeMs;
- if (totalTimeMs > timePeriodMs) {
+ if (totalTimeMs > timePeriodMs + SAMPLE_ERROR_MILLIS) {
StringBuilder sb = new StringBuilder();
sb.append("Total time ");
TimeUtils.formatDuration(totalTimeMs, sb);
diff --git a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
index 74ba404..aca6991 100644
--- a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
+++ b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
@@ -20,6 +20,7 @@
import android.net.LinkProperties;
import android.net.Network;
+import android.net.NetworkUtils;
import android.net.RouteInfo;
import android.os.SystemClock;
import android.system.ErrnoException;
@@ -79,6 +80,10 @@
public class NetworkDiagnostics {
private static final String TAG = "NetworkDiagnostics";
+ private static final InetAddress TEST_DNS4 = NetworkUtils.numericToInetAddress("8.8.8.8");
+ private static final InetAddress TEST_DNS6 = NetworkUtils.numericToInetAddress(
+ "2001:4860:4860::8888");
+
// For brevity elsewhere.
private static final long now() {
return SystemClock.elapsedRealtime();
@@ -156,6 +161,21 @@
mStartTime = now();
mDeadlineTime = mStartTime + mTimeoutMs;
+ // Hardcode measurements to TEST_DNS4 and TEST_DNS6 in order to test off-link connectivity.
+ // We are free to modify mLinkProperties with impunity because ConnectivityService passes us
+ // a copy and not the original object. It's easier to do it this way because we don't need
+ // to check whether the LinkProperties already contains these DNS servers because
+ // LinkProperties#addDnsServer checks for duplicates.
+ if (mLinkProperties.isReachable(TEST_DNS4)) {
+ mLinkProperties.addDnsServer(TEST_DNS4);
+ }
+ // TODO: we could use mLinkProperties.isReachable(TEST_DNS6) here, because we won't set any
+ // DNS servers for which isReachable() is false, but since this is diagnostic code, be extra
+ // careful.
+ if (mLinkProperties.hasGlobalIPv6Address() || mLinkProperties.hasIPv6DefaultRoute()) {
+ mLinkProperties.addDnsServer(TEST_DNS6);
+ }
+
for (RouteInfo route : mLinkProperties.getRoutes()) {
if (route.hasGateway()) {
prepareIcmpMeasurement(route.getGateway());
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 23cb767..6707562 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -529,6 +529,7 @@
@Override
public void setUserRestriction(String key, boolean value, int userId) {
+ checkManageUsersPermission("setUserRestriction");
synchronized (mPackagesLock) {
if (!SYSTEM_CONTROLLED_RESTRICTIONS.contains(key)) {
Bundle restrictions = getUserRestrictions(userId);
diff --git a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
index ba1231f..da1df1a 100644
--- a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
+++ b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
@@ -21,12 +21,13 @@
import android.net.LinkAddress;
import android.system.OsConstants;
import android.test.suitebuilder.annotation.SmallTest;
-import junit.framework.TestCase;
+import com.android.internal.util.HexDump;
import java.net.Inet4Address;
import java.nio.ByteBuffer;
import java.util.ArrayList;
+import junit.framework.TestCase;
import libcore.util.HexEncoding;
import static android.net.dhcp.DhcpPacket.*;
@@ -370,4 +371,69 @@
assertDhcpResults("172.17.152.118/16", "172.17.1.1", "172.17.1.1",
null, "1.1.1.1", null, 43200, false, dhcpResults);
}
+
+ @SmallTest
+ public void testBug2111() throws Exception {
+ final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
+ // IP header.
+ "4500014c00000000ff119beac3eaf3880a3f5d04" +
+ // UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
+ "0043004401387464" +
+ // BOOTP header.
+ "0201060002554812000a0000000000000a3f5d040000000000000000" +
+ // MAC address.
+ "00904c00000000000000000000000000" +
+ // Server name.
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ // File.
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ // Options.
+ "638253633501023604c00002fe33040000bfc60104fffff00003040a3f50010608c0000201c0000202" +
+ "0f0f646f6d61696e3132332e636f2e756b0000000000ff00000000"
+ ).toCharArray(), false));
+
+ DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
+ assertTrue(offerPacket instanceof DhcpOfferPacket);
+ DhcpResults dhcpResults = offerPacket.toDhcpResults();
+ assertDhcpResults("10.63.93.4/20", "10.63.80.1", "192.0.2.1,192.0.2.2",
+ "domain123.co.uk", "192.0.2.254", null, 49094, false, dhcpResults);
+ }
+
+ @SmallTest
+ public void testBug2136() throws Exception {
+ final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
+ // Ethernet header.
+ "bcf5ac000000d0c7890000000800" +
+ // IP header.
+ "4500014c00000000ff119beac3eaf3880a3f5d04" +
+ // UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
+ "0043004401387574" +
+ // BOOTP header.
+ "0201060163339a3000050000000000000a209ecd0000000000000000" +
+ // MAC address.
+ "bcf5ac00000000000000000000000000" +
+ // Server name.
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ // File.
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ // Options.
+ "6382536335010236040a20ff80330400001c200104fffff00003040a20900106089458413494584135" +
+ "0f0b6c616e63732e61632e756b000000000000000000ff00000000"
+ ).toCharArray(), false));
+
+ DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
+ assertTrue(offerPacket instanceof DhcpOfferPacket);
+ assertEquals("BCF5AC000000", HexDump.toHexString(offerPacket.getClientMac()));
+ DhcpResults dhcpResults = offerPacket.toDhcpResults();
+ assertDhcpResults("10.32.158.205/20", "10.32.144.1", "148.88.65.52,148.88.65.53",
+ "lancs.ac.uk", "10.32.255.128", null, 7200, false, dhcpResults);
+ }
}