diff options
81 files changed, 2547 insertions, 1017 deletions
diff --git a/CleanSpec.mk b/CleanSpec.mk index 8711ad7..2287859 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -135,6 +135,7 @@ $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framew $(call add-clean-step, rm -f $(PRODUCT_OUT)/system/media/video/Disco*) $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates) $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/ImageProcessing_intermediates) +$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/ImageProcessing2_intermediates) # ************************************************ # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST # ************************************************ @@ -27448,6 +27448,7 @@ package android.webkit { method public void setInitialScale(int); method public deprecated void setMapTrackballToArrowKeys(boolean); method public void setNetworkAvailable(boolean); + method public deprecated void setPictureListener(android.webkit.WebView.PictureListener); method public void setVerticalScrollbarOverlay(boolean); method public void setWebChromeClient(android.webkit.WebChromeClient); method public void setWebViewClient(android.webkit.WebViewClient); diff --git a/api/current.txt b/api/current.txt index 7cadf9b..7b2f161 100644 --- a/api/current.txt +++ b/api/current.txt @@ -27448,6 +27448,7 @@ package android.webkit { method public void setInitialScale(int); method public deprecated void setMapTrackballToArrowKeys(boolean); method public void setNetworkAvailable(boolean); + method public deprecated void setPictureListener(android.webkit.WebView.PictureListener); method public void setVerticalScrollbarOverlay(boolean); method public void setWebChromeClient(android.webkit.WebChromeClient); method public void setWebViewClient(android.webkit.WebViewClient); diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index c455b7d..463a18c 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -990,7 +990,10 @@ public final class Pm { } name = arg; try { - if (mUm.createUser(name, 0) == null) { + final UserInfo info = mUm.createUser(name, 0); + if (info != null) { + System.out.println("Success: created user id " + info.id); + } else { System.err.println("Error: couldn't create User."); } } catch (RemoteException e) { diff --git a/core/java/android/service/dreams/Sandman.java b/core/java/android/service/dreams/Sandman.java new file mode 100644 index 0000000..70142ce --- /dev/null +++ b/core/java/android/service/dreams/Sandman.java @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2012 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.service.dreams; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.os.PowerManager; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.SystemClock; +import android.os.UserHandle; +import android.provider.Settings; +import android.util.Slog; + +/** + * Internal helper for launching dreams to ensure consistency between the + * <code>UiModeManagerService</code> system service and the <code>Somnambulator</code> activity. + * + * @hide + */ +public final class Sandman { + private static final String TAG = "Sandman"; + + private static final int DEFAULT_SCREENSAVER_ENABLED = 1; + private static final int DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK = 1; + + // The component name of a special dock app that merely launches a dream. + // We don't want to launch this app when docked because it causes an unnecessary + // activity transition. We just want to start the dream. + private static final ComponentName SOMNAMBULATOR_COMPONENT = + new ComponentName("com.android.systemui", "com.android.systemui.Somnambulator"); + + + // The sandman is eternal. No one instantiates him. + private Sandman() { + } + + /** + * Returns true if the specified dock app intent should be started. + * False if we should dream instead, if appropriate. + */ + public static boolean shouldStartDockApp(Context context, Intent intent) { + ComponentName name = intent.resolveActivity(context.getPackageManager()); + return name != null && !name.equals(SOMNAMBULATOR_COMPONENT); + } + + /** + * Starts a dream manually. + */ + public static void startDreamByUserRequest(Context context) { + startDream(context, false); + } + + /** + * Starts a dream when docked if the system has been configured to do so, + * otherwise does nothing. + */ + public static void startDreamWhenDockedIfAppropriate(Context context) { + if (!isScreenSaverEnabled(context) + || !isScreenSaverActivatedOnDock(context)) { + Slog.i(TAG, "Dreams currently disabled for docks."); + return; + } + + startDream(context, true); + } + + private static void startDream(Context context, boolean docked) { + try { + IDreamManager dreamManagerService = IDreamManager.Stub.asInterface( + ServiceManager.getService(DreamService.DREAM_SERVICE)); + if (dreamManagerService != null && !dreamManagerService.isDreaming()) { + if (docked) { + Slog.i(TAG, "Activating dream while docked."); + + // Wake up. + // The power manager will wake up the system automatically when it starts + // receiving power from a dock but there is a race between that happening + // and the UI mode manager starting a dream. We want the system to already + // be awake by the time this happens. Otherwise the dream may not start. + PowerManager powerManager = + (PowerManager)context.getSystemService(Context.POWER_SERVICE); + powerManager.wakeUp(SystemClock.uptimeMillis()); + } else { + Slog.i(TAG, "Activating dream by user request."); + } + + // Dream. + dreamManagerService.dream(); + } + } catch (RemoteException ex) { + Slog.e(TAG, "Could not start dream when docked.", ex); + } + } + + private static boolean isScreenSaverEnabled(Context context) { + return Settings.Secure.getIntForUser(context.getContentResolver(), + Settings.Secure.SCREENSAVER_ENABLED, DEFAULT_SCREENSAVER_ENABLED, + UserHandle.USER_CURRENT) != 0; + } + + private static boolean isScreenSaverActivatedOnDock(Context context) { + return Settings.Secure.getIntForUser(context.getContentResolver(), + Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK, + DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK, UserHandle.USER_CURRENT) != 0; + } +} diff --git a/core/java/android/webkit/AccessibilityInjector.java b/core/java/android/webkit/AccessibilityInjector.java index d6576e1..357a16e 100644 --- a/core/java/android/webkit/AccessibilityInjector.java +++ b/core/java/android/webkit/AccessibilityInjector.java @@ -96,11 +96,26 @@ class AccessibilityInjector { // Template for JavaScript that performs AndroidVox actions. private static final String ACCESSIBILITY_ANDROIDVOX_TEMPLATE = - "cvox.AndroidVox.performAction('%1s')"; + "(function() {" + + " if ((typeof(cvox) != 'undefined')"+ + " && (typeof(cvox.ChromeVox) != 'undefined')" + + " && (typeof(cvox.AndroidVox) != 'undefined')" + + " && cvox.ChromeVox.isActive) {" + + " return cvox.AndroidVox.performAction('%1s');" + + " } else {" + + " return false;" + + " }" + + "})()"; // JS code used to shut down an active AndroidVox instance. private static final String TOGGLE_CVOX_TEMPLATE = - "javascript:(function() { cvox.ChromeVox.host.activateOrDeactivateChromeVox(%b); })();"; + "javascript:(function() {" + + " if ((typeof(cvox) != 'undefined')"+ + " && (typeof(cvox.ChromeVox) != 'undefined')" + + " && (typeof(cvox.ChromeVox.host) != 'undefined')) {" + + " cvox.ChromeVox.host.activateOrDeactivateChromeVox(%b);" + + " }" + + "})();"; /** * Creates an instance of the AccessibilityInjector based on @@ -776,20 +791,26 @@ class AccessibilityInjector { while (true) { try { if (mResultId == resultId) { + if (DEBUG) + Log.w(TAG, "Received CVOX result"); return true; } if (mResultId > resultId) { + if (DEBUG) + Log.w(TAG, "Obsolete CVOX result"); return false; } final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis; waitTimeMillis = RESULT_TIMEOUT - elapsedTimeMillis; if (waitTimeMillis <= 0) { + if (DEBUG) + Log.w(TAG, "Timed out while waiting for CVOX result"); return false; } mResultLock.wait(waitTimeMillis); } catch (InterruptedException ie) { if (DEBUG) - Log.w(TAG, "Timed out while waiting for CVOX result"); + Log.w(TAG, "Interrupted while waiting for CVOX result"); /* ignore */ } } @@ -805,6 +826,8 @@ class AccessibilityInjector { @JavascriptInterface @SuppressWarnings("unused") public void onResult(String id, String result) { + if (DEBUG) + Log.w(TAG, "Saw CVOX result of '" + result + "'"); final long resultId; try { diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 4202a7f..6df7820 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -1480,7 +1480,6 @@ public class WebView extends AbsoluteLayout * * @param listener an implementation of WebView.PictureListener * @deprecated This method is now obsolete. - * @hide Since API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1} */ @Deprecated public void setPictureListener(PictureListener listener) { diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java index d68511c..7d0d0ba 100644 --- a/core/java/android/webkit/WebViewClassic.java +++ b/core/java/android/webkit/WebViewClassic.java @@ -5185,7 +5185,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc if (cm.hasPrimaryClip()) { Point cursorPoint = new Point(contentToViewX(mSelectCursorBase.x), contentToViewY(mSelectCursorBase.y)); - Point cursorTop = calculateCaretTop(); + Point cursorTop = calculateBaseCaretTop(); cursorTop.set(contentToViewX(cursorTop.x), contentToViewY(cursorTop.y)); @@ -5229,17 +5229,22 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc return scale; } + private Point calculateBaseCaretTop() { + return calculateCaretTop(mSelectCursorBase, mSelectCursorBaseTextQuad); + } + + private Point calculateDraggingCaretTop() { + return calculateCaretTop(mSelectDraggingCursor, mSelectDraggingTextQuad); + } + /** * Assuming arbitrary shape of a quadralateral forming text bounds, this * calculates the top of a caret. */ - private Point calculateCaretTop() { - float scale = scaleAlongSegment(mSelectCursorBase.x, mSelectCursorBase.y, - mSelectCursorBaseTextQuad.p4, mSelectCursorBaseTextQuad.p3); - int x = Math.round(scaleCoordinate(scale, - mSelectCursorBaseTextQuad.p1.x, mSelectCursorBaseTextQuad.p2.x)); - int y = Math.round(scaleCoordinate(scale, - mSelectCursorBaseTextQuad.p1.y, mSelectCursorBaseTextQuad.p2.y)); + private static Point calculateCaretTop(Point base, QuadF quad) { + float scale = scaleAlongSegment(base.x, base.y, quad.p4, quad.p3); + int x = Math.round(scaleCoordinate(scale, quad.p1.x, quad.p2.x)); + int y = Math.round(scaleCoordinate(scale, quad.p1.y, quad.p2.y)); return new Point(x, y); } @@ -5269,12 +5274,20 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc return true; } - private void updateWebkitSelection() { + private void updateWebkitSelection(boolean isSnapped) { int handleId = (mSelectDraggingCursor == mSelectCursorBase) ? HANDLE_ID_BASE : HANDLE_ID_EXTENT; + int x = mSelectDraggingCursor.x; + int y = mSelectDraggingCursor.y; + if (isSnapped) { + // "center" the cursor in the snapping quad + Point top = calculateDraggingCaretTop(); + x = Math.round((top.x + x) / 2); + y = Math.round((top.y + y) / 2); + } mWebViewCore.removeMessages(EventHub.SELECT_TEXT); mWebViewCore.sendMessageAtFrontOfQueue(EventHub.SELECT_TEXT, - mSelectDraggingCursor.x, mSelectDraggingCursor.y, (Integer)handleId); + x, y, (Integer)handleId); } private void resetCaretTimer() { @@ -5616,7 +5629,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc Math.max(0, mEditTextContentBounds.top - buffer), mEditTextContentBounds.right + buffer, mEditTextContentBounds.bottom + buffer); - Point caretTop = calculateCaretTop(); + Point caretTop = calculateBaseCaretTop(); if (visibleRect.width() < mEditTextContentBounds.width()) { // The whole edit won't fit in the width, so use the caret rect if (mSelectCursorBase.x < caretTop.x) { @@ -5947,10 +5960,12 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc } else { endScrollEdit(); } + boolean snapped = false; if (inCursorText || (mIsEditingText && !inEditBounds)) { snapDraggingCursor(); + snapped = true; } - updateWebkitSelection(); + updateWebkitSelection(snapped); if (!inCursorText && mIsEditingText && inEditBounds) { // Visually snap even if we have moved the handle. snapDraggingCursor(); @@ -6277,7 +6292,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc int oldX = mSelectDraggingCursor.x; int oldY = mSelectDraggingCursor.y; mSelectDraggingCursor.set(selectionX, selectionY); - updateWebkitSelection(); + updateWebkitSelection(false); scrollEditText(scrollX, scrollY); mSelectDraggingCursor.set(oldX, oldY); } diff --git a/core/jni/android_os_UEventObserver.cpp b/core/jni/android_os_UEventObserver.cpp index 7033ff3..3f7c7d2 100644 --- a/core/jni/android_os_UEventObserver.cpp +++ b/core/jni/android_os_UEventObserver.cpp @@ -49,7 +49,7 @@ static bool isMatch(const char* buffer, size_t length) { // Consider all zero-delimited fields of the buffer. const char* field = buffer; - const char* end = buffer + length; + const char* end = buffer + length + 1; do { if (strstr(field, match.string())) { ALOGV("Matched uevent message with pattern: %s", match.string()); diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 9ce7f8a..384f1ab 100755 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -1197,8 +1197,8 @@ <!-- A coordinate in the Y dimension. --> <attr name="y" format="dimension" /> - <!-- Specifies how to place the content of an object, both - on the x- and y-axis, within the object itself. --> + <!-- Specifies how an object should position its content, on both the X and Y axes, + within its own bounds. --> <attr name="gravity"> <!-- Push object to the top of its container, not changing its size. --> <flag name="top" value="0x30" /> @@ -1257,8 +1257,8 @@ <!-- Reference to an array resource that will populate a list/adapter. --> <attr name="entries" format="reference" /> - <!-- Standard gravity constant that a child can supply to its parent. - Defines how to place the view, both its x- and y-axis, within its parent view group. --> + <!-- Standard gravity constant that a child supplies to its parent. + Defines how the child view should be positioned, on both the X and Y axes, within its enclosing layout. --> <attr name="layout_gravity"> <!-- Push object to the top of its container, not changing its size. --> <flag name="top" value="0x30" /> diff --git a/data/sounds/AudioPackage8.mk b/data/sounds/AudioPackage8.mk new file mode 100755 index 0000000..93c43da --- /dev/null +++ b/data/sounds/AudioPackage8.mk @@ -0,0 +1,70 @@ +# +# Audio Package 7 - Tuna +# +# Include this file in a product makefile to include these audio files +# +# + +LOCAL_PATH:= frameworks/base/data/sounds + +PRODUCT_COPY_FILES += \ + $(LOCAL_PATH)/alarms/ogg/Cesium.ogg:system/media/audio/alarms/Cesium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Fermium.ogg:system/media/audio/alarms/Fermium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Hassium.ogg:system/media/audio/alarms/Hassium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Neptunium.ogg:system/media/audio/alarms/Neptunium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Nobelium.ogg:system/media/audio/alarms/Nobelium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Osmium.ogg:system/media/audio/alarms/Osmium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Plutonium.ogg:system/media/audio/alarms/Plutonium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Promethium.ogg:system/media/audio/alarms/Promethium.ogg \ + $(LOCAL_PATH)/effects/ogg/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressStandard_120.ogg:system/media/audio/ui/KeypressStandard.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120.ogg:system/media/audio/ui/KeypressSpacebar.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressDelete_120.ogg:system/media/audio/ui/KeypressDelete.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressReturn_120.ogg:system/media/audio/ui/KeypressReturn.ogg \ + $(LOCAL_PATH)/effects/ogg/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \ + $(LOCAL_PATH)/effects/ogg/camera_click.ogg:system/media/audio/ui/camera_click.ogg \ + $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \ + $(LOCAL_PATH)/effects/ogg/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \ + $(LOCAL_PATH)/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg \ + $(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \ + $(LOCAL_PATH)/effects/ogg/Lock.ogg:system/media/audio/ui/Lock.ogg \ + $(LOCAL_PATH)/effects/ogg/Unlock.ogg:system/media/audio/ui/Unlock.ogg \ + $(LOCAL_PATH)/notifications/ogg/Adara.ogg:system/media/audio/notifications/Adara.ogg \ + $(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:system/media/audio/notifications/Arcturus.ogg \ + $(LOCAL_PATH)/notifications/ogg/Bellatrix.ogg:system/media/audio/notifications/Bellatrix.ogg \ + $(LOCAL_PATH)/notifications/ogg/Capella.ogg:system/media/audio/notifications/Capella.ogg \ + $(LOCAL_PATH)/notifications/ogg/CetiAlpha.ogg:system/media/audio/notifications/CetiAlpha.ogg \ + $(LOCAL_PATH)/notifications/ogg/Hojus.ogg:system/media/audio/notifications/Hojus.ogg \ + $(LOCAL_PATH)/notifications/ogg/Lalande.ogg:system/media/audio/notifications/Lalande.ogg \ + $(LOCAL_PATH)/notifications/ogg/Mira.ogg:system/media/audio/notifications/Mira.ogg \ + $(LOCAL_PATH)/notifications/ogg/Polaris.ogg:system/media/audio/notifications/Polaris.ogg \ + $(LOCAL_PATH)/notifications/ogg/Pollux.ogg:system/media/audio/notifications/Pollux.ogg \ + $(LOCAL_PATH)/notifications/ogg/Procyon.ogg:system/media/audio/notifications/Procyon.ogg \ + $(LOCAL_PATH)/notifications/ogg/Proxima.ogg:system/media/audio/notifications/Proxima.ogg \ + $(LOCAL_PATH)/notifications/ogg/Shaula.ogg:system/media/audio/notifications/Shaula.ogg \ + $(LOCAL_PATH)/notifications/ogg/Spica.ogg:system/media/audio/notifications/Spica.ogg \ + $(LOCAL_PATH)/notifications/ogg/Tejat.ogg:system/media/audio/notifications/Tejat.ogg \ + $(LOCAL_PATH)/notifications/ogg/Upsilon.ogg:system/media/audio/notifications/Upsilon.ogg \ + $(LOCAL_PATH)/notifications/ogg/Vega.ogg:system/media/audio/notifications/Vega.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:system/media/audio/ringtones/Andromeda.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:system/media/audio/ringtones/Aquila.ogg \ + $(LOCAL_PATH)/ringtones/ogg/ArgoNavis.ogg:system/media/audio/ringtones/ArgoNavis.ogg \ + $(LOCAL_PATH)/ringtones/ogg/CanisMajor.ogg:system/media/audio/ringtones/CanisMajor.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Carina.ogg:system/media/audio/ringtones/Carina.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Centaurus.ogg:system/media/audio/ringtones/Centaurus.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Cygnus.ogg:system/media/audio/ringtones/Cygnus.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Draco.ogg:system/media/audio/ringtones/Draco.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Girtab.ogg:system/media/audio/ringtones/Girtab.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Hydra.ogg:system/media/audio/ringtones/Hydra.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Machina.ogg:system/media/audio/ringtones/Machina.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Orion.ogg:system/media/audio/ringtones/Orion.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Pegasus.ogg:system/media/audio/ringtones/Pegasus.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Perseus.ogg:system/media/audio/ringtones/Perseus.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Pyxis.ogg:system/media/audio/ringtones/Pyxis.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Rigel.ogg:system/media/audio/ringtones/Rigel.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Scarabaeus.ogg:system/media/audio/ringtones/Scarabaeus.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Sceptrum.ogg:system/media/audio/ringtones/Sceptrum.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Solarium.ogg:system/media/audio/ringtones/Solarium.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Themos.ogg:system/media/audio/ringtones/Themos.ogg \ + $(LOCAL_PATH)/ringtones/ogg/UrsaMinor.ogg:system/media/audio/ringtones/UrsaMinor.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Zeta.ogg:system/media/audio/ringtones/Zeta.ogg diff --git a/data/sounds/alarms/ogg/Fermium.ogg b/data/sounds/alarms/ogg/Fermium.ogg Binary files differindex fecc2ba..d8f6124 100644 --- a/data/sounds/alarms/ogg/Fermium.ogg +++ b/data/sounds/alarms/ogg/Fermium.ogg diff --git a/data/sounds/alarms/ogg/Hassium.ogg b/data/sounds/alarms/ogg/Hassium.ogg Binary files differindex 260bf7d..793c269 100644 --- a/data/sounds/alarms/ogg/Hassium.ogg +++ b/data/sounds/alarms/ogg/Hassium.ogg diff --git a/data/sounds/alarms/ogg/Neptunium.ogg b/data/sounds/alarms/ogg/Neptunium.ogg Binary files differindex b1ea741..d99f133 100644 --- a/data/sounds/alarms/ogg/Neptunium.ogg +++ b/data/sounds/alarms/ogg/Neptunium.ogg diff --git a/data/sounds/alarms/ogg/Osmium.ogg b/data/sounds/alarms/ogg/Osmium.ogg Binary files differnew file mode 100644 index 0000000..4c76080 --- /dev/null +++ b/data/sounds/alarms/ogg/Osmium.ogg diff --git a/data/sounds/alarms/ogg/Promethium.ogg b/data/sounds/alarms/ogg/Promethium.ogg Binary files differnew file mode 100644 index 0000000..2a195a3 --- /dev/null +++ b/data/sounds/alarms/ogg/Promethium.ogg diff --git a/data/sounds/alarms/wav/Fermium.wav b/data/sounds/alarms/wav/Fermium.wav Binary files differindex 0174884..56e57fc 100644 --- a/data/sounds/alarms/wav/Fermium.wav +++ b/data/sounds/alarms/wav/Fermium.wav diff --git a/data/sounds/alarms/wav/Hassium.wav b/data/sounds/alarms/wav/Hassium.wav Binary files differindex e3992cf..17710b0 100644 --- a/data/sounds/alarms/wav/Hassium.wav +++ b/data/sounds/alarms/wav/Hassium.wav diff --git a/data/sounds/alarms/wav/Neptunium.wav b/data/sounds/alarms/wav/Neptunium.wav Binary files differindex cf3684a..2b855e1 100644 --- a/data/sounds/alarms/wav/Neptunium.wav +++ b/data/sounds/alarms/wav/Neptunium.wav diff --git a/data/sounds/alarms/wav/Osmium.wav b/data/sounds/alarms/wav/Osmium.wav Binary files differnew file mode 100755 index 0000000..2dcc47f --- /dev/null +++ b/data/sounds/alarms/wav/Osmium.wav diff --git a/data/sounds/alarms/wav/Promethium.wav b/data/sounds/alarms/wav/Promethium.wav Binary files differnew file mode 100755 index 0000000..08ea03e --- /dev/null +++ b/data/sounds/alarms/wav/Promethium.wav diff --git a/docs/html/guide/topics/ui/notifiers/notifications.jd b/docs/html/guide/topics/ui/notifiers/notifications.jd index 273b5f7..fbff532 100644 --- a/docs/html/guide/topics/ui/notifiers/notifications.jd +++ b/docs/html/guide/topics/ui/notifiers/notifications.jd @@ -1,646 +1,902 @@ -page.title=Status Notifications -parent.title=Notifications -parent.link=index.html +page.title=Notifications @jd:body <div id="qv-wrapper"> - <div id="qv"> - <h2>Quickview</h2> - <ul> - <li>A status notification allows your application to notify the user of an event -without interupting their current activity</li> - <li>You can attach an intent to your notification that the system will initiate when the -user clicks it</li> - </ul> - - <h2>In this document</h2> +<div id="qv"> +<h2>In this document</h2> <ol> - <li><a href="#Basics">The Basics</a></li> - <li><a href="#HandlingNotifications">Responding to Notifications</a></li> - <li><a href="#ManageYourNotifications">Managing your Notifications</a></li> - <li><a href="#CreateANotification">Creating a Notification</a> - <ol> - <li><a href="#Updating">Updating the notification</a></li> - <li><a href="#Sound">Adding a sound</a></li> - <li><a href="#Vibration">Adding vibration</a></li> - <li><a href="#Lights">Adding flashing lights</a></li> - <li><a href="#More">More features</a></li> - </ol> - </li> - <li><a href="#CustomExpandedView">Creating a Custom Notification Layout</a></li> + <li> + <a href="#NotificationUI">Notification Display Elements</a> + </li> + <li> + <a href="#CreateNotification">Creating a Notification</a> + </li> + <li> + <a href="#Managing">Managing Notifications</a> + </li> + <li> + <a href="#NotificationResponse">Preserving Navigation when Starting an Activity</a> + </li> + <li> + <a href="#Progress">Displaying Progress in a Notification</a> + </li> + <li> + <a href="#CustomNotification">Custom Notification Layouts</a> + </li> </ol> <h2>Key classes</h2> <ol> - <li>{@link android.app.Notification}</li> - <li>{@link android.app.NotificationManager}</li> + <li>{@link android.app.NotificationManager}</li> + <li>{@link android.support.v4.app.NotificationCompat}</li> </ol> - - <h2>See also</h2> + <h2>Videos</h2> <ol> - <li><a href="{@docRoot}design/patterns/notifications.html">Android -Design: Notifications</a></li> + <li> + <a href="http://www.youtube.com/watch?v=Yc8YrVc47TI&feature=player_detailpage#t=1672s"> + Notifications in 4.1</a> + </li> </ol> - </div> +<h2>See also</h2> +<ol> + <li> + <a href="{@docRoot}design/patterns/notifications.html">Android Design: Notifications</a> + </li> +</ol> </div> - -<p>A status notification adds an icon to the system's status bar -(with an optional ticker-text message) and a notification message in the notifications window. -When the user selects the notification, Android fires an -{@link android.content.Intent} that is defined by the {@link android.app.Notification} (usually to -launch an {@link android.app.Activity}). -You can also configure the notification to alert the user with a sound, a vibration, and flashing -lights on the device.</p> - -<p>A status notification should be used for any case in -which a background service needs to alert the user about an event that requires a response. A -background service -<strong>should never</strong> launch an activity on its own in order to receive user interaction. -The service should instead create a status notification that will launch the activity -when selected by the user.</p> - -<p>Figure 1 shows the status bar with a notification icon on the left side.</p> -<img src="{@docRoot}images/status_bar.png" alt="" /> -<p class="img-caption"><strong>Figure 1.</strong> Status bar with a notification.</p> - -<p>Figure 2 shows the notification's message in the notifications window.</p> - -<img src="{@docRoot}images/notifications_window.png" alt="" /> -<p class="img-caption"><strong>Figure 2.</strong> The notifications window.</p> - - +</div> +<p> + A notification is a message you can display to the user outside of your application's + normal UI. When you tell the system to issue a notification, it first appears as an icon in the + <strong>notification area</strong>. To see the details of the notification, the user opens the + <strong>notification drawer</strong>. Both the notification area and the notification drawer + are system-controlled areas that the user can view at any time. +</p> +<img + id="figure1" + src="{@docRoot}images/ui/notifications/iconic_notification.png" + height="32" + alt="" /> +<p class="img-caption"> + <strong>Figure 1.</strong> Notifications in the notification area. +</p> +<img id="figure2" src="{@docRoot}images/ui/notifications/normal_notification.png" + height="240" alt="" /> +<p class="img-caption"> + <strong>Figure 2.</strong> Notifications in the notification drawer. +</p> <div class="note design"> -<p><strong>Notification Design</strong></p> - <p>For design guidelines, read Android Design's <a -href="{@docRoot}design/patterns/notifications.html">Notifications</a> guide.</p> + <p> + <strong>Notification Design</strong> + </p> + <p> + Notifications, as an important part of the Android UI, have their own design guidelines. To + learn how to design notifications and their interactions, read the Android Design Guide + <a href="{@docRoot}design/patterns/notifications.html">Notifications</a> topic. + </p> </div> - - - -<h2 id="Basics">The Basics</h2> - -<p>An {@link android.app.Activity} or {@link android.app.Service} can initiate a status -notification. Because an activity can perform actions only while it is -running in the foreground and its window has focus, you will usually create status notifications -from a -service. This way, the notification can be created from the background, -while the user is using another application or -while the device is asleep. To create a notification, you must use two -classes: {@link android.app.Notification} and {@link android.app.NotificationManager}.</p> - -<p>Use an instance of the {@link android.app.Notification} class to define the properties of your -status notification, such as the status icon, the notification message, and extra settings -such as a sound to play. The {@link android.app.NotificationManager} is an Android system service -that executes and manages all status notifications. You do not instantiate the -{@link android.app.NotificationManager} directly. In order -to give it your {@link android.app.Notification}, you must retrieve a reference to the -{@link android.app.NotificationManager} with -{@link android.app.Activity#getSystemService(String) getSystemService()} and -then, when you want to notify the user, pass it your {@link android.app.Notification} with -{@link android.app.NotificationManager#notify(int,Notification) notify()}. </p> - -<p>To create a status notification:</p> -<ol> - <li>Get a reference to the {@link android.app.NotificationManager}: -<pre> -String ns = Context.NOTIFICATION_SERVICE; -NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns); -</pre> - </li> - <!-- use Notification.Builder in 3.0 --> - <li>Instantiate the {@link android.app.Notification}: -<pre> -int icon = R.drawable.notification_icon; -CharSequence tickerText = "Hello"; -long when = System.currentTimeMillis(); - -Notification notification = new Notification(icon, tickerText, when); -</pre> - </li> - <li>Define the notification's message and {@link android.app.PendingIntent}: -<pre> -Context context = getApplicationContext(); -CharSequence contentTitle = "My notification"; -CharSequence contentText = "Hello World!"; -Intent notificationIntent = new Intent(this, MyClass.class); -PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); - -notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent); -</pre> - </li> - <li>Pass the {@link android.app.Notification} to the {@link android.app.NotificationManager}: -<pre> -private static final int HELLO_ID = 1; - -mNotificationManager.notify(HELLO_ID, notification); -</pre> - <p>That's it. Your user has now been notified.</p> - </li> -</ol> - - -<h2 id="HandlingNotifications">Responding to Notifications</h2> - -<p>A central part of the user's experience with a notification revolves around -how it interacts with the application's UI flow. You must implement -this correctly to provide a consistent user experience within your app.</p> - -<p>Two typical examples of notifications are provided by Calendar, which can send out -notifications of upcoming events, and Email, which can send out notifications -when new messages arrive. These represent the two recommended patterns for handling -notifications: either launching into an activity that is separate from the -main application, or launching an entirely new instance of the application -showing the appropriate point for the notification.</p> - -<p>The following scenario shows how the activity stack should work -in these two typical notification flows, first handling a Calendar notification: +<p class="note"> + <strong>Note:</strong> This guide refers to the + {@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder} class + in the version 4 <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>. + The class {@link android.app.Notification.Builder Notification.Builder} was added in API + level 11. +</p> +<!-- ------------------------------------------------------------------------------------------ --> +<!-- ------------------------------------------------------------------------------------------ --> +<h2 id="NotificationUI">Notification Display Elements</h2> +<p> + Notifications in the notification drawer appear in two main visual styles, normal view and + big view. +</p> +<!-- ------------------------------------------------------------------------------------------ --> +<h3 id="NormalNotify">Normal view</h3> +<p> + A notification in normal view appears in an area that's up to 64 dp tall. Even if you create a + notification with a big view style, it will appear in normal view until it's expanded. This + is an example of a normal view: +</p> +<img + src="{@docRoot}images/ui/notifications/normal_notification_callouts.png" + alt="" + height="204" + id="figure3" /> +<p class="img-caption"> + <strong>Figure 3.</strong> Notification in normal view. +</p> +<p> + The callouts in the illustration refer to the following: </p> - -<ol> - <li>User is creating a new event in Calendar. They realize they - need to copy part of an email message into this event. - </li> - <li> - The user chooses Home > Email. - </li> - <li> - While in Email, they receive a notification from Calendar for an upcoming - meeting. - </li> - <li> - So they choose that notification, which takes them to a - dedicated Calendar activity that displays brief details of the - upcoming meeting. - </li> - <li> - The user has seen enough to know they have a meeting coming up, - so they press the <em>Back</em> button. They are now returned to Email, which - is where they were when they took the notification. - </li> -</ol> - -<p>Handling an Email notification:</p> - <ol> - <li> - The user is currently in Email composing a message, and needs to - check a date in their calendar. - </li> - <li> - The user chooses Home > Calendar. - </li> - <li> - While in Calendar, they receive a notification from Email about a new - message. - </li> - <li> - They select the notification, which brings them to Email with the message - details displayed. This has replaced what they were previously doing - (writing an e-mail), but that message is still saved in their drafts. - </li> - <li> - The user presses <em>Back</em> once to go to the message list (the typical flow in the - Email app), and press <em>Back</em> again to return to Calendar as they left it. - </li> + <li>Content title</li> + <li>Large icon</li> + <li>Content text</li> + <li>Content info</li> + <li>Small icon</li> + <li> + Time that the notification was issued. You can set an explicit value with + {@link android.support.v4.app.NotificationCompat.Builder#setWhen setWhen()}; if you don't + it defaults to the time that the system received the notification. + </li> </ol> - -<p>In an Email style of notification, the UI launched by the notification -shows the main application in a state representing that notification. -For example, when the Email application comes to the foreground from its -notification, it displays either the conversion list or a specific -conversation depending on whether there are multiple or only one new -email. To achieve this, we want to completely replace whatever current -state the application is in with a new activity stack representing the -new notification state.</p> - -<p>The following code illustrates how to show this kind of notification. Of -most interest is the <code>makeMessageIntentStack()</code> method, which constructs -an array of intents representing the app's new activity stack for this state. -(If you are using fragments, you may need to initialize your fragment and -app state so that pressing <em>Back</em> will switch the UI back to its parent state.) -The core of this is the {@link android.content.Intent#makeRestartActivityTask -Intent.makeRestartActivityTask()} method, which constructs the root activity -of the stack with the appropriate flags, such as -{@link android.content.Intent#FLAG_ACTIVITY_CLEAR_TASK Intent.FLAG_ACTIVITY_CLEAR_TASK}.</p> - -{@sample development/samples/ApiDemos/src/com/example/android/apis/app/IncomingMessage.java - app_notification} - -<p>In a Calendar style of notification, the UI launched by the notification -is a dedicated activity that is not part of the normal application flow. -For example, when the user receives a Calendar notification, choosing that -notification starts a special activity that displays a list -of upcoming calendar events — this view is available only -from the notification, not through the Calendar's normal user -interface.</p> - -<p>The code for posting this type of notification is very straight-forward; it -is like the above, but the {@link android.app.PendingIntent} is for just a single -activity, our dedicated notification activity.</p> - -{@sample development/samples/ApiDemos/src/com/example/android/apis/app/IncomingMessage.java - interstitial_notification} - -<p>This is not enough, however. Normally Android considers all activities within -an application to be part of that application's UI flow, so simply launching the -activity like this can cause it to be mixed with your normal application back stack -in undesired ways. To make it behave correctly, in the manifest declaration -for the activity the attributes -<code>android:launchMode="singleTask"</code>, -<code>android:taskAffinity=""</code> and -<code>android:excludeFromRecents="true"</code> -must be set. The full activity declaration for this sample is:</p> - -{@sample development/samples/ApiDemos/AndroidManifest.xml interstitial_affinity} - -<p>You must be careful when launching other activities from this initial activity, -because this is not a top-level part of the application, does not appear in -recents, and needs to be relaunched at any point from the notification with new data -to show. This best approach is to make sure any activity launched from it is -launched in its own task. When doing this care must be taken to make sure this -new task interacts well with the current state of your exiting application's -task. This is essentially -the same as switching to the main application as described for the Email style -notification shown before. Given the <code>makeMessageIntentStack()</code> -method previously shown, handling a click then would look something like this:</p> - -{@sample development/samples/ApiDemos/src/com/example/android/apis/app/IncomingMessageInterstitial.java - app_launch} - -<h2 id="ManageYourNotifications">Managing your Notifications</h2> - -<p>The {@link android.app.NotificationManager} is a system service that manages all -notifications. You must retrieve a reference to it with the -{@link android.app.Activity#getSystemService(String) getSystemService()} method. -For example:</p> -<pre> -String ns = Context.NOTIFICATION_SERVICE; -NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns); -</pre> - -<p>When you want to deliver your status notification, pass the {@link android.app.Notification} -to the {@link android.app.NotificationManager} with {@link -android.app.NotificationManager#notify(int,Notification)}. -The first parameter is the unique ID for the notification and the second is the {@link -android.app.Notification} object. -The ID uniquely identifies the notification from within your -application. The ID is necessary if you need to update the notification or (if -your application manages different kinds of notifications) select the appropriate action -when the user returns to your application via the intent defined in the notification.</p> - -<p>To clear the status notification when the user selects it from the notifications -window, add the "FLAG_AUTO_CANCEL" flag to your {@link android.app.Notification}. You can -also clear it manually with {@link android.app.NotificationManager#cancel(int)}, passing it the -notification ID, or clear all your notifications with {@link -android.app.NotificationManager#cancelAll()}.</p> - - -<h2 id="CreateANotification">Creating a Notification</h2> - -<p>A {@link android.app.Notification} object defines the details of the notification -message that is displayed in the status bar and notifications window, and any other -alert settings, such as sounds and blinking lights.</p> - -<p>A status notification <em>requires</em> all of the following:</p> -<ul> - <li>An icon for the status bar</li> - <li>A title and message, unless you define a - <a href="#CustomExpandedView">custom notification layout</a></li> - <li>A {@link android.app.PendingIntent}, to be fired when the notification is selected</li> -</ul> -<p>Optional settings for the status notification include:</p> +<!-- ------------------------------------------------------------------------------------------ --> +<h3 id="BigNotify">Big view</h3> +<p> + A notification's big view appears only when the notification is expanded, which happens when the + notification is at the top of the notification drawer, or when the user expands the + notification with a gesture. +</p> +<p> + The following screenshot shows an inbox-style notification: +</p> +<img src="{@docRoot}images/ui/notifications/bigpicture_notification_callouts.png" + alt="" + height="240" + id="figure4" /> +<p class="img-caption"> + <strong>Figure 4.</strong> Big view notification. +</p> +<p> + Notice that the big view shares most of its visual elements with the normal view. The + only difference is callout number 7, the details area. Each big view style sets this area in + a different way. The available styles are: +</p> +<dl> + <dt> + Big picture style + </dt> + <dd> + The details area contains a bitmap up to 256 dp tall in its detail section. + </dd> + <dt> + Big text style + </dt> + <dd> + Displays a large text block in the details section. + </dd> + <dt> + Inbox style + </dt> + <dd> + Displays lines of text in the details section. + </dd> +</dl> +<p> + All of the big view styles also have the following content options that aren't + available in normal view: +</p> +<dl> + <dt> + Big content title + </dt> + <dd> + Allows you to override the normal view's content title with a title that appears only in + the expanded view. + </dd> + <dt> + Summary text + </dt> + <dd> + Allows you to add a line of text below the details area. + </dd> +</dl> +<p> + Applying a big view style to a notification is described in the section + <a href="#ApplyStyle">Applying a big view style to a notification</a>. +</p> +<!-- ------------------------------------------------------------------------------------------ --> +<!-- ------------------------------------------------------------------------------------------ --> +<h2 id="CreateNotification">Creating a Notification</h2> +<p> + You specify the UI information and actions for a notification in a + {@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder} object. + To create the notification itself, you call + {@link android.support.v4.app.NotificationCompat.Builder#build + NotificationCompat.Builder.build()}, which returns a {@link android.app.Notification} object + containing your specifications. + To issue the notification, you pass the {@link android.app.Notification} object to the system + by calling {@link android.app.NotificationManager#notify NotificationManager.notify()}. +</p> +<!-- ------------------------------------------------------------------------------------------ --> +<h3 id="Required">Required notification contents</h3> +<p> + A {@link android.app.Notification} object <em>must</em> contain the following: +</p> <ul> - <li>A ticker-text message for the status bar</li> - <li>An alert sound</li> - <li>A vibrate setting</li> - <li>A flashing LED setting</li> + <li> + A small icon, set by + {@link android.support.v4.app.NotificationCompat.Builder#setSmallIcon setSmallIcon()} + </li> + <li> + A title, set by + {@link android.support.v4.app.NotificationCompat.Builder#setContentTitle setContentTitle()} + </li> + <li> + Detail text, set by + {@link android.support.v4.app.NotificationCompat.Builder#setContentText setContentText()} + </li> </ul> - -<p>The starter-kit for a new notification includes the -{@link android.app.Notification#Notification(int,CharSequence,long)} constructor and the -{@link android.app.Notification#setLatestEventInfo(Context,CharSequence,CharSequence,PendingIntent)} -method. These define all the required settings for a notification. -The following snippet demonstrates a basic notification setup:</p> -<pre> -int icon = R.drawable.notification_icon; // icon from resources -CharSequence tickerText = "Hello"; // ticker-text -long when = System.currentTimeMillis(); // notification time -Context context = getApplicationContext(); // application Context -CharSequence contentTitle = "My notification"; // message title -CharSequence contentText = "Hello World!"; // message text - -Intent notificationIntent = new Intent(this, MyClass.class); -PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); - -// the next two lines initialize the Notification, using the configurations above -Notification notification = new Notification(icon, tickerText, when); -notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent); -</pre> - - -<h3 id="Updating">Updating the notification</h3> - -<p>You can update the information in your status notification as events -continue to occur in your application. For example, when a new SMS text message arrives -before previous messages have been read, the Messaging application updates the existing -notification to display the total number of new messages received. -This practice of updating an existing notification is much better than adding new -notifications, because it avoids clutter in the notifications window.</p> - -<p>Because each notification is uniquely identified -by the {@link android.app.NotificationManager} with an integer ID, you can revise the notification -by calling {@link -android.app.Notification#setLatestEventInfo(Context,CharSequence,CharSequence,PendingIntent) -setLatestEventInfo()} with new values, change some field values of the notification, and then call -{@link android.app.NotificationManager#notify(int,Notification) notify()} again.</p> - -<p>You can revise each property with the object member fields -(except for the {@link android.content.Context} and the notification title and text). You -should always revise the text message when you update the notification by calling -{@link android.app.Notification#setLatestEventInfo(Context,CharSequence,CharSequence,PendingIntent) -setLatestEventInfo()} with new values for <var>contentTitle</var> and <var>contentText</var>. -Then call {@link android.app.NotificationManager#notify(int,Notification) notify()} to update the -notification. (Of course, if you've created a <a href="#CustomExpandedView">custom notification -layout</a>, then updating these title and text values has no effect.)</p> - - -<h3 id="Sound">Adding a sound</h3> - -<p>You can alert the user with the default notification sound -(which is defined by the user) or with a sound specified by your application.</p> - -<p>To use the user's default sound, add "DEFAULT_SOUND" to the <var>defaults</var> field:</p> -<pre> -notification.defaults |= Notification.DEFAULT_SOUND; -</pre> - -<p>To use a different sound with your notifications, pass a Uri reference to the -<var>sound</var> field. -The following example uses a known audio file saved to the device SD card:</p> -<pre> -notification.sound = Uri.parse("file:///sdcard/notification/ringer.mp3"); -</pre> - -<p>In the next example, the audio file is chosen from the internal -{@link android.provider.MediaStore.Audio.Media MediaStore}'s {@link android.content.ContentProvider}:</p> +<h3 id="Optional">Optional notification contents and settings</h3> +<p> + All other notification settings and contents are optional. To learn more about them, + see the reference documentation for {@link android.support.v4.app.NotificationCompat.Builder}. +</p> +<!-- ------------------------------------------------------------------------------------------ --> +<h3 id="Actions">Notification actions</h3> +<p> + Although they're optional, you should add at least one action to your notification. + An action allows users to go directly from the notification to an + {@link android.app.Activity} in your application, where they can look at one or more events + or do further work. +</p> +<p> + A notification can provide multiple actions. You should always define the action that's + triggered when the user touches the notification; usually this action opens an + {@link android.app.Activity} in your application. You can also add buttons to the notification + that perform additional actions such as snoozing an alarm or responding immediately to a text + message. +</p> +<p> + Inside a {@link android.app.Notification}, the action itself is defined by a + {@link android.app.PendingIntent} containing an {@link android.content.Intent} that starts + an {@link android.app.Activity} in your application. To associate the + {@link android.app.PendingIntent} with a gesture, call the appropriate method of + {@link android.support.v4.app.NotificationCompat.Builder}. For example, if you want to start + {@link android.app.Activity} when the user touches the notification text in + the notification drawer, you add the {@link android.app.PendingIntent} by calling + {@link android.support.v4.app.NotificationCompat.Builder#setContentIntent setContentIntent()}. +</p> +<p> + Starting an {@link android.app.Activity} when the user touches the notification is the most + common action scenario. You can also start an {@link android.app.Activity} when the user + dismisses an {@link android.app.Activity}, and you can start an {@link android.app.Activity} + from an action button. To learn more, read the reference guide for + {@link android.support.v4.app.NotificationCompat.Builder}. +</p> +<!-- ------------------------------------------------------------------------------------------ --> +<h3 id="SimpleNotification">Creating a simple notification</h3> +<p> + The following snippet illustrates a simple notification that specifies an activity to open when + the user touches the notification. Notice that the code creates a + {@link android.support.v4.app.TaskStackBuilder} object and uses it to create the + {@link android.app.PendingIntent} for the action. This pattern is explained in more detail + in the section <a href="#NotificationResponse"> + Preserving Navigation when Starting an Activity</a>: +</p> <pre> -notification.sound = Uri.withAppendedPath(Audio.Media.INTERNAL_CONTENT_URI, "6"); +NotificationCompat.Builder mBuilder = + new NotificationCompat.Builder(this) + .setSmallIcon(R.drawable.notification_icon) + .setContentTitle("My notification") + .setContentText("Hello World!"); +// Creates an explicit intent for an Activity in your app +Intent resultIntent = new Intent(this, ResultActivity.class); + +// The stack builder object will contain an artificial back stack for the +// started Activity. +// This ensures that navigating backward from the Activity leads out of +// your application to the Home screen. +TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); +// Adds the back stack for the Intent (but not the Intent itself) +stackBuilder.addParentStack(ResultActivity.class); +// Adds the Intent that starts the Activity to the top of the stack +stackBuilder.addNextIntent(resultIntent); +PendingIntent resultPendingIntent = + stackBuilder.getPendingIntent( + 0, + PendingIntent.FLAG_UPDATE_CURRENT + ); +mBuilder.setContentIntent(resultPendingIntent); +NotificationManager mNotificationManager = + (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); +// mId allows you to update the notification later on. +mNotificationManager.notify(mId, mBuilder.build()); </pre> - -<p>In this case, the exact ID of the media file ("6") is known and appended to the content -{@link android.net.Uri}. If you don't know the exact ID, you must query all the -media available in the {@link android.provider.MediaStore} with a {@link -android.content.ContentResolver}. -See the <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a> -documentation for more information on using a ContentResolver.</p> - -<p>If you want the sound to continuously repeat until the user responds to the notification -or the notification is cancelled, add {@link android.app.Notification#FLAG_INSISTENT} to the -<var>flags</var> field.</p> - -<p class="note"><strong>Note:</strong> If the <var>defaults</var> field includes -{@link android.app.Notification#DEFAULT_SOUND}, then the default sound overrides any sound defined -by the <var>sound</var> field.</p> - - -<h3 id="Vibration">Adding vibration</h3> - -<p>You can alert the user with the the default -vibration pattern or with a vibration pattern defined by your application.</p> - -<p>To use the default pattern, add {@link android.app.Notification#DEFAULT_VIBRATE} to the -<var>defaults</var> field:</p> +<p>That's it. Your user has now been notified.</p> +<!-- ------------------------------------------------------------------------------------------ --> +<h3 id="ApplyStyle">Applying a big view style to a notification</h3> +<p> + To have a notification appear in a big view when it's expanded, first create a + {@link android.support.v4.app.NotificationCompat.Builder} object with the normal view options + you want. Next, call {@link android.support.v4.app.NotificationCompat.Builder#setStyle + Builder.setStyle()} with a big view style object as its argument. +</p> +<p> + For example, the following code snippet demonstrates how to alter the notification created + in the previous snippet to use the Inbox big view style: +</p> <pre> -notification.defaults |= Notification.DEFAULT_VIBRATE; +NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this) + .setSmallIcon(R.drawable.notification_icon) + .setContentTitle("Event tracker") + .setContentText("Events received") +NotificationCompat.InboxStyle inboxStyle = + new NotificationCompat.InboxStyle(); +String[] events = new String[6]; +// Sets a title for the Inbox style big view +inboxStyle.SetBigContentTitle("Event tracker details:"); +... +// Moves events into the big view +for (int i=0; i < events.length; i++) { + + inboxStyle.addLine(events[i]); +} +// Moves the big view style object into the notification object. +mBuilder.setStyle(inBoxStyle); +... +// Issue the notification here. </pre> - -<p>To define your own vibration pattern, pass an array of <em>long</em> values to the -<var>vibrate</var> field:</p> +<!-- ------------------------------------------------------------------------------------------ --> +<!-- ------------------------------------------------------------------------------------------ --> +<h2 id="Managing">Managing Notifications</h2> +<p> + When you need to issue a notification multiple times for the same type of event, you + should avoid making a completely new notification. Instead, you should consider updating a + previous notification, either by changing some of its values or by adding to it, or both. +</p> +<p> + For example, Gmail notifies the user that new emails have arrived by increasing its count of + unread messages and by adding a summary of each email to the notification. This is called + "stacking" the notification; it's described in more detail in the + <a href="{@docRoot}design/patterns/notifications.html">Notifications</a> Design guide. +</p> +<p> + The following section describes how to update notifications and also how to remove them. +</p> +<h3 id="Updating">Updating notifications</h3> +<p> + To set up a notification so it can be updated, issue it with a notification ID by + calling {@link android.app.NotificationManager#notify(int, Notification) + NotificationManager.notify(ID, notification)}. To update this notification once you've issued + it, update or create a {@link android.support.v4.app.NotificationCompat.Builder} object, + build a {@link android.app.Notification} object from it, and issue the + {@link android.app.Notification} with the same ID you used previously. If + the previous notification is still visible, the system updates it from the contents of + the {@link android.app.Notification} object. If the previous notification has been dismissed, a + new notification is created instead. +</p> +<p> + The following snippet demonstrates a notification that is updated to reflect the + number of events that have occurred. It stacks the notification, showing a summary: +</p> <pre> -long[] vibrate = {0,100,200,300}; -notification.vibrate = vibrate; +mNotificationManager = + (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); +// Sets an ID for the notification, so it can be updated +int notifyID = 1; +mNotifyBuilder = new NotificationCompat.Builder(this) + .setContentTitle("New Message") + .setContentText("You've received new messages.") + .setSmallIcon(R.drawable.ic_notify_status) +numMessages = 0; +// Start of a loop that processes data and then notifies the user +... + mNotifyBuilder.setContentText(currentText) + .setNumber(++numMessages); + // Because the ID remains unchanged, the existing notification is + // updated. + mNotificationManager.notify( + notifyID, + mNotifyBuilder.build()); +... </pre> - -<p>The long array defines the alternating pattern for the length of vibration off and on -(in milliseconds). The first value is how long to wait (off) before beginning, the second -value is the length of the first vibration, the third is the next length off, and so on. -The pattern can be as long as you like, but it can't be set to repeat. +<p> + This produces a notification that looks like this: </p> - -<p class="note"><strong>Note:</strong> If the <var>defaults</var> field includes -{@link android.app.Notification#DEFAULT_VIBRATE}, then the default vibration overrides any vibration -defined by the -<var>vibrate</var> field.</p> - - -<h3 id="Lights">Adding flashing lights</h3> - -<p>To alert the user by flashing LED lights, you can implement the default -light pattern (if available), or define your own color and pattern for the lights.</p> - -<p>To use the default light setting, add {@link android.app.Notification#DEFAULT_LIGHTS} to the -<var>defaults</var> field:</p> +<img + id="figure5" + src="{@docRoot}images/ui/notifications/updated_notification.png" + alt="" + height="118"/> +<p class="img-caption"> + <strong>Figure 5.</strong> Updated notification displayed in the notification drawer. +</p> +<!-- ------------------------------------------------------------------------------------------ --> +<h3 id="Removing">Removing notifications</h3> +<p> + Notifications remain visible until one of the following happens: +</p> +<ul> + <li> + The user dismisses the notification either individually or by using "Clear All" (if + the notification can be cleared). + </li> + <li> + The user touches the notification, and you called + {@link android.support.v4.app.NotificationCompat.Builder#setAutoCancel setAutoCancel()} when + you created the notification. + </li> + <li> + You call {@link android.app.NotificationManager#cancel(int) cancel()} for a specific + notification ID. This method also deletes ongoing notifications. + </li> + <li> + You call {@link android.app.NotificationManager#cancelAll() cancelAll()}, which removes + all of the notifications you previously issued. + </li> +</ul> +<!-- ------------------------------------------------------------------------------------------ --> +<!-- ------------------------------------------------------------------------------------------ --> +<h2 id="NotificationResponse">Preserving Navigation when Starting an Activity</h2> +<p> + When you start an {@link android.app.Activity} from a notification, you must preserve the + user's expected navigation experience. Clicking <i>Back</i> should take the user back through + the application's normal work flow to the Home screen, and clicking <i>Recents</i> should show + the {@link android.app.Activity} as a separate task. To preserve the navigation experience, you + should start the {@link android.app.Activity} in a fresh task. How you set up the + {@link android.app.PendingIntent} to give you a fresh task depends on the nature of the + {@link android.app.Activity} you're starting. There are two general situations: +</p> +<dl> + <dt> + Regular activity + </dt> + <dd> + You're starting an {@link android.app.Activity} that's part of the application's normal + workflow. In this situation, set up the {@link android.app.PendingIntent} to + start a fresh task, and provide the {@link android.app.PendingIntent} with a back stack + that reproduces the application's normal <i>Back</i> behavior. + <p> + Notifications from the Gmail app demonstrate this. When you touch a notification for + a single email message, you see the message itself. Touching <b>Back</b> takes you + backwards through Gmail to the Home screen, just as if you had entered Gmail from the + Home screen rather than entering it from a notification. + </p> + <p> + This happens regardless of the application you were in when you touched the + notification. For example, if you're in Gmail composing a message, and you click a + notification for a single email, you go immediately to that email. Touching <i>Back</i> + takes you to the inbox and then the Home screen, rather than taking you to the + message you were composing. + </p> + </dd> + <dt> + Special activity + </dt> + <dd> + The user only sees this {@link android.app.Activity} if it's started from a notification. + In a sense, the {@link android.app.Activity} extends the notification by providing + information that would be hard to display in the notification itself. For this situation, + set up the {@link android.app.PendingIntent} to start in a fresh task. There's no need to + create a back stack, though, because the started {@link android.app.Activity} isn't part of + the application's activity flow. Clicking <i>Back</i> will still take the user to the + Home screen. + </dd> +</dl> +<!-- ------------------------------------------------------------------------------------------ --> +<h3 id="DirectEntry">Setting up a regular activity PendingIntent</h3> +<p> + To set up a {@link android.app.PendingIntent} that starts a direct entry + {@link android.app.Activity}, follow these steps: +</p> +<ol> + <li> + Define your application's {@link android.app.Activity} hierarchy in the manifest. + <ol style="list-style-type: lower-alpha;"> + <li> + Add support for API versions 15 and earlier. To do this, specify the parent of the + {@link android.app.Activity} you're starting by adding a +<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html"><meta-data></a></code> + element as the child of the +<code><a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code>. + <p> + For this element, set +<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html#nm">android:name</a>="android.support.PARENT_ACTIVITY"</code>. + Set +<code><a href="{@docRoot}/guide/topics/manifest/meta-data-element.html#val">android:value</a>="<parent_activity_name>"</code> + where <code><parent_activity_name></code> is the value of +<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html#nm">android:name</a></code> + for the parent +<code><a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code> + element. See the following XML for an example. + </p> + </li> + <li> + Also add support for API versions 16 and later. To do this, add the +<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#parent">android:parentActivityName</a></code> + attribute to the +<code><a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code> + element of the {@link android.app.Activity} you're starting. + </li> + </ol> + <p> + The final XML should look like this: + </p> <pre> -notification.defaults |= Notification.DEFAULT_LIGHTS; +<activity + android:name=".MainActivity" + android:label="@string/app_name" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> +</activity> +<activity + android:name=".ResultActivity" + android:parentActivityName=".MainActivity"> + <meta-data + android:name="android.support.PARENT_ACTIVITY" + android:value=".MainActivity"/> +</activity> </pre> - -<p>To define your own color and pattern, define a value for the <var>ledARGB</var> field -(for the color), the <var>ledOffMS</var> field (length of time, in milliseconds, to -keep the light off), the <var>ledOnMS</var> (length of time, in milliseconds, to keep the light on), -and also add {@link android.app.Notification#FLAG_SHOW_LIGHTS} to the <var>flags</var> field:</p> + </li> + <li> + Create a back stack based on the {@link android.content.Intent} that starts the + {@link android.app.Activity}: + <ol style="list-style-type: lower-alpha;"> + <li> + Create the {@link android.content.Intent} to start the {@link android.app.Activity}. + </li> + <li> + Create a stack builder by calling {@link android.app.TaskStackBuilder#create + TaskStackBuilder.create()}. + </li> + <li> + Add the back stack to the stack builder by calling + {@link android.support.v4.app.TaskStackBuilder#addParentStack addParentStack()}. + For each {@link android.app.Activity} in the hierarchy you've defined in the + manifest, the back stack contains an {@link android.content.Intent} object that + starts the {@link android.app.Activity}. This method also adds flags that start the + stack in a fresh task. + <p class="note"> + <strong>Note:</strong> Although the argument to + {@link android.support.v4.app.TaskStackBuilder#addParentStack addParentStack()} + is a reference to the started {@link android.app.Activity}, the method call + doesn't add the {@link android.content.Intent} that starts the + {@link android.app.Activity}. Instead, that's taken care of in the next step. + </p> + </li> + <li> + Add the {@link android.content.Intent} that starts the {@link android.app.Activity} + from the notification, by calling + {@link android.support.v4.app.TaskStackBuilder#addNextIntent addNextIntent()}. + Pass the {@link android.content.Intent} you created in the first step as the + argument to + {@link android.support.v4.app.TaskStackBuilder#addNextIntent addNextIntent()}. + </li> + <li> + If you need to, add arguments to {@link android.content.Intent} objects on the + stack by calling {@link android.support.v4.app.TaskStackBuilder#editIntentAt + TaskStackBuilder.editIntentAt()}. This is sometimes necessary to ensure that the + target {@link android.app.Activity} displays meaningful data when the user navigates + to it using <i>Back</i>. + </li> + <li> + Get a {@link android.app.PendingIntent} for this back stack by calling + {@link android.support.v4.app.TaskStackBuilder#getPendingIntent getPendingIntent()}. + You can then use this {@link android.app.PendingIntent} as the argument to + {@link android.support.v4.app.NotificationCompat.Builder#setContentIntent + setContentIntent()}. + </li> + </ol> + </li> +</ol> +<p> + The following code snippet demonstrates the process: +</p> <pre> -notification.ledARGB = 0xff00ff00; -notification.ledOnMS = 300; -notification.ledOffMS = 1000; -notification.flags |= Notification.FLAG_SHOW_LIGHTS; +... +Intent resultIntent = new Intent(this, ResultActivity.class); +TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); +// Adds the back stack +stackBuilder.addParentStack(ResultActivity.class); +// Adds the Intent to the top of the stack +stackBuilder.addNextIntent(resultIntent); +// Gets a PendingIntent containing the entire back stack +PendingIntent resultPendingIntent = + stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT); +... +NotificationCompat.Builder builder = new NotificationCompat.Builder(this); +builder.setContentIntent(resultPendingIntent); +NotificationManager mNotificationManager = + (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); +mNotificationManager.notify(id, builder.build()); </pre> - -<p>In this example, the green light repeatedly flashes on for 300 milliseconds and -turns off for one second. Not every color in the spectrum is supported by the -device LEDs, and not every device supports the same colors, so the hardware -estimates to the best of its ability. Green is the most common notification color.</p> - - -<h3 id="More">More features</h3> - -<p>You can add several more features to your notifications -using {@link android.app.Notification} fields and flags. Some useful features include the -following:</p> - -<dl> - <dt>{@link android.app.Notification#FLAG_AUTO_CANCEL} flag</dt> - <dd>Add this to the <var>flags</var> field to automatically cancel the notification - after it is selected from the notifications window.</dd> - <dt>{@link android.app.Notification#FLAG_INSISTENT} flag</dt> - <dd>Add this to the <var>flags</var> field to repeat the audio until the - user responds.</dd> - <dt>{@link android.app.Notification#FLAG_ONGOING_EVENT} flag</dt> - <dd>Add this to the <var>flags</var> field to group the notification under the "Ongoing" - title in the notifications window. This indicates that the application is on-going — - its processes are still running in the background, even when the application is not - visible (such as with music or a phone call).</dd> - <dt>{@link android.app.Notification#FLAG_NO_CLEAR} flag</dt> - <dd>Add this to the <var>flags</var> field to indicate that the notification should - <em>not</em> be cleared by the "Clear notifications" button. This is particularly useful if - your notification is on-going.</dd> - <dt>{@link android.app.Notification#number} field</dt> - <dd>This value indicates the current number of events represented by the notification. - The appropriate number is overlaid on top of the status icon. - If you intend to use this field, then you must start with "1" when the Notification is first - created. (If you change the value from zero to anything greater during an update, the number - is not shown.)</dd> - <dt>{@link android.app.Notification#iconLevel} field</dt> - <dd>This value indicates the current level of a - {@link android.graphics.drawable.LevelListDrawable} that is used for the notification icon. - You can animate the icon in the status bar by changing this value to correlate with the - drawable's defined in a LevelListDrawable. See the {@link android.graphics.drawable.LevelListDrawable} - reference for more information.</dd> -</dl> - -<p>See the {@link android.app.Notification} class reference for more information about additional -features that you can customize for your application.</p> - - -<h2 id="CustomExpandedView">Creating a Custom Notification Layout</h2> - -<div class="figure" style="width:200px;margin-top:0"> -<img src="{@docRoot}images/custom_message.png" alt="" /> -<p class="img-caption"><strong>Figure 3.</strong> Notification with a custom layout.</p> -</div> - -<p>By default, the notification that appears in the notifications window includes a title -and the message text. -These are defined by the <var>contentTitle</var> and <var>contentText</var> -parameters of the {@link android.app.Notification#setLatestEventInfo(Context,CharSequence,CharSequence,PendingIntent) -setLatestEventInfo()} method. However, you can also define a custom layout for the -notification using -{@link android.widget.RemoteViews}. Figure 3 shows an example of a -custom notification layout. It looks similar to the default notification, but is -actually created with a custom XML layout.</p> - -<p>To define your own layout for the notification, -instantiate a {@link android.widget.RemoteViews} object that inflates a custom layout file, then -pass the {@link android.widget.RemoteViews} to the <var>contentView</var> field of your -Notification.</p> - -<p>Creating a custom notification layout is best understood with an example:</p> - +<!-- ------------------------------------------------------------------------------------------ --> +<h3 id="ExtendedNotification">Setting up a special activity PendingIntent</h3> +<p> + The following section describes how to set up a special activity + {@link android.app.PendingIntent}. +</p> +<p> + A special {@link android.app.Activity} doesn't need a back stack, so you don't have to + define its {@link android.app.Activity} hierarchy in the manifest, and you don't have + to call + {@link android.support.v4.app.TaskStackBuilder#addParentStack addParentStack()} to build a + back stack. Instead, use the manifest to set up the {@link android.app.Activity} task options, + and create the {@link android.app.PendingIntent} by calling + {@link android.app.PendingIntent#getActivity getActivity()}: +</p> <ol> - <li>Create the XML layout for the notification. - For example, the following layout is called <code>custom_notification.xml</code>: + <li> + In your manifest, add the following attributes to the +<code><a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code> + element for the {@link android.app.Activity} + <dl> + <dt> +<code><a href="guide/topics/manifest/activity-element.html#nm">android:name</a>="<i>activityclass</i>"</code> + </dt> + <dd> + The activity's fully-qualified class name. + </dd> + <dt> +<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#aff">android:taskAffinity</a>=""</code> + </dt> + <dd> + Combined with the + {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK FLAG_ACTIVITY_NEW_TASK} flag + that you set in code, this ensures that this {@link android.app.Activity} doesn't + go into the application's default task. Any existing tasks that have the + application's default affinity are not affected. + </dd> + <dt> +<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#exclude">android:excludeFromRecents</a>="true"</code> + </dt> + <dd> + Excludes the new task from <i>Recents</i>, so that the user can't accidentally + navigate back to it. + </dd> + </dl> + <p> + This snippet shows the element: + </p> <pre> -<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/layout" - android:layout_width="fill_parent" - android:layout_height="fill_parent" - android:padding="10dp" > - <ImageView android:id="@+id/image" - android:layout_width="wrap_content" - android:layout_height="fill_parent" - android:layout_alignParentLeft="true" - android:layout_marginRight="10dp" /> - <TextView android:id="@+id/title" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_toRightOf="@id/image" - style="@style/NotificationTitle" /> - <TextView android:id="@+id/text" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_toRightOf="@id/image" - android:layout_below="@id/title" - style="@style/NotificationText" /> -</RelativeLayout> +<activity + android:name=".ResultActivity" +... + android:launchMode="singleTask" + android:taskAffinity="" + android:excludeFromRecents="true"> +</activity> +... </pre> - - <p>Notice that the two {@link android.widget.TextView} elements include the {@code style} -attribute. It's important that you use style resources for the text in your custom -notifications, because the background color of the notification can vary across different -devices and platform versions. Beginning with Android 2.3 (API level 9), the system defines a -style for the text it uses for the default notification layouts. Thus, you should apply -that style when running on Android 2.3 or higher to ensure that your text is visible against -the background.</p> - - <p>For example, to use the standard text colors on versions of Android lower than 2.3, you -should use the following styles for {@code res/values/styles.xml}:</p> + </li> + <li> + Build and issue the notification: + <ol style="list-style-type: lower-alpha;"> + <li> + Create an {@link android.content.Intent} that starts the + {@link android.app.Activity}. + </li> + <li> + Set the {@link android.app.Activity} to start in a new, empty task by calling + {@link android.content.Intent#setFlags setFlags()} with the flags + {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK FLAG_ACTIVITY_NEW_TASK} + and + {@link android.content.Intent#FLAG_ACTIVITY_CLEAR_TASK FLAG_ACTIVITY_CLEAR_TASK}. + </li> + <li> + Set any other options you need for the {@link android.content.Intent}. + </li> + <li> + Create a {@link android.app.PendingIntent} from the {@link android.content.Intent} + by calling {@link android.app.PendingIntent#getActivity getActivity()}. + You can then use this {@link android.app.PendingIntent} as the argument to + {@link android.support.v4.app.NotificationCompat.Builder#setContentIntent + setContentIntent()}. + </li> + </ol> + <p> + The following code snippet demonstrates the process: + </p> <pre> -<?xml version="1.0" encoding="utf-8"?> -<resources> - <style name="NotificationText"> - <item name="android:textColor">?android:attr/textColorPrimary</item> - </style> - <style name="NotificationTitle"> - <item name="android:textColor">?android:attr/textColorPrimary</item> - <item name="android:textStyle">bold</item> - </style> - <!-- If you want a slightly different color for some text, - consider using ?android:attr/textColorSecondary --> -</resources> +// Instantiate a Builder object. +NotificationCompat.Builder builder = new NotificationCompat.Builder(this); +// Creates an Intent for the Activity +Intent notifyIntent = + new Intent(new ComponentName(this, ResultActivity.class)); +// Sets the Activity to start in a new, empty task +notifyIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK); +// Creates the PendingIntent +PendingIntent notifyIntent = + PendingIntent.getActivity( + this, + 0, + notifyIntent + PendingIntent.FLAG_UPDATE_CURRENT +); + +// Puts the PendingIntent into the notification builder +builder.setContentIntent(notifyIntent); +// Notifications are issued by sending them to the +// NotificationManager system service. +NotificationManager mNotificationManager = + (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); +// Builds an anonymous Notification object from the builder, and +// passes it to the NotificationManager +mNotificationManager.notify(id, builder.build()); </pre> - <p>Then, to apply the system's default colors for notifications on Android -2.3 and higher, use the following styles for {@code res/values-v9/styles.xml}:</p> + </li> +</ol> +<!-- ------------------------------------------------------------------------------------------ --> +<!-- ------------------------------------------------------------------------------------------ --> +<h2 id="Progress">Displaying Progress in a Notification</h2> +<p> + Notifications can include an animated progress indicator that shows users the status + of an ongoing operation. If you can estimate how long the operation takes and how much of it + is complete at any time, use the "determinate" form of the indicator + (a progress bar). If you can't estimate the length of the operation, use the + "indeterminate" form of the indicator (an activity indicator). +</p> +<p> + Progress indicators are displayed with the platform's implementation of the + {@link android.widget.ProgressBar} class. +</p> +<p> + To use a progress indicator, call + {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()}. The + determinate and indeterminate forms are described in the following sections. +</p> +<!-- ------------------------------------------------------------------------------------------ --> +<h3 id="FixedProgress">Displaying a fixed-duration progress indicator</h3> +<p> + To display a determinate progress bar, add the bar to your notification by calling + {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress() + setProgress(max, progress, false)} and then issue the notification. As your operation proceeds, + increment <code>progress</code>, and update the notification. At the end of the operation, + <code>progress</code> should equal <code>max</code>. A common way to call + {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()} + is to set <code>max</code> to 100 and then increment <code>progress</code> as a + "percent complete" value for the operation. +</p> +<p> + You can either leave the progress bar showing when the operation is done, or remove it. In + either case, remember to update the notification text to show that the operation is complete. + To remove the progress bar, call + {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress() + setProgress(0, 0, false)}. For example: +</p> <pre> -<?xml version="1.0" encoding="utf-8"?> -<resources> - <style name="NotificationText" parent="android:TextAppearance.StatusBar.EventContent" /> - <style name="NotificationTitle" parent="android:TextAppearance.StatusBar.EventContent.Title" /> -</resources> +... +mNotifyManager = + (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); +mBuilder = new NotificationCompat.Builder(this); +mBuilder.setContentTitle("Picture Download") + .setContentText("Download in progress") + .setSmallIcon(R.drawable.ic_notification); +// Start a lengthy operation in a background thread +new Thread( + new Runnable() { + @Override + public void run() { + int incr; + // Do the "lengthy" operation 20 times + for (incr = 0; incr <= 100; incr+=5) { + // Sets the progress indicator to a max value, the + // current completion percentage, and "determinate" + // state + mBuilder.setProgress(100, incr, false); + // Displays the progress bar for the first time. + mNotifyManager.notify(0, mBuilder.build()); + // Sleeps the thread, simulating an operation + // that takes time + try { + // Sleep for 5 seconds + Thread.sleep(5*1000); + } catch (InterruptedException e) { + Log.d(TAG, "sleep failure"); + } + } + // When the loop is finished, updates the notification + mBuilder.setContentText("Download complete") + // Removes the progress bar + .setProgress(0,0,false); + mNotifyManager.notify(ID, mBuilder.build()); + } + } +// Starts the thread by calling the run() method in its Runnable +).start(); </pre> - <p>Now, when running on Android 2.3 (API level 9) or higher, the text in your custom view will -use the same colors that the system does for default notifications. This is important because later -versions of Android actually change the background color of the notifications to be dark. Inheriting -the system's styles ensures that your text will be light in such cases, but also if the background -is some other unexpected color, your text will also change as appropriate.</p> - </li> - - <li>Now, in the application code, use the RemoveViews - methods to define the image and text. Then pass the RemoteViews object to the <var>contentView</var> - field of the Notification, as shown in this example: +<p> + The resulting notifications are shown in figure 6. On the left side is a snapshot of the + notification during the operation; on the right side is a snapshot of it after the operation + has finished. +</p> +<img + id="figure6" + src="{@docRoot}images/ui/notifications/progress_bar_summary.png" + height="84" + alt="" /> +<p class="img-caption"> +<strong>Figure 6.</strong> The progress bar during and after the operation.</p> +<!-- ------------------------------------------------------------------------------------------ --> +<h3 id="ActivityIndicator">Displaying a continuing activity indicator</h3> +<p> + To display an indeterminate activity indicator, add it to your notification with + {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress(0, 0, true)} + (the first two arguments are ignored), and issue the notification. The result is an indicator + that has the same style as a progress bar, except that its animation is ongoing. +</p> +<p> + Issue the notification at the beginning of the operation. The animation will run until you + modify your notification. When the operation is done, call + {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress() + setProgress(0, 0, false)} and then update the notification to remove the activity indicator. + Always do this; otherwise, the animation will run even when the operation is complete. Also + remember to change the notification text to indicate that the operation is complete. +</p> +<p> + To see how activity indicators work, refer to the preceding snippet. Locate the following lines: +</p> <pre> -RemoteViews contentView = new RemoteViews(getPackageName(), R.layout.custom_notification_layout); -contentView.setImageViewResource(R.id.image, R.drawable.notification_image); -contentView.setTextViewText(R.id.title, "Custom notification"); -contentView.setTextViewText(R.id.text, "This is a custom layout"); -notification.contentView = contentView; +// Sets the progress indicator to a max value, the current completion +// percentage, and "determinate" state +mBuilder.setProgress(100, incr, false); +// Issues the notification +mNotifyManager.notify(0, mBuilder.build()); </pre> - - <p>As shown here, pass the application's package name and the layout - resource ID to the RemoteViews constructor. Then, define the content for the ImageView and TextView, - using the {@link android.widget.RemoteViews#setImageViewResource(int, int) setImageViewResource()} - and {@link android.widget.RemoteViews#setTextViewText(int, CharSequence) setTextViewText()}. - In each case, pass the reference ID of the appropriate View object that you want to set, along with - the value for that View. Finally, the RemoteViews object is passed to the Notification in the - <var>contentView</var> field.</p> - </li> - - <li>Because you don't need the - {@link android.app.Notification#setLatestEventInfo(Context,CharSequence,CharSequence,PendingIntent) - setLatestEventInfo()} method when using a custom view, you must define the Intent for the Notification - with the <var>contentIntent</var> field, as in this example: +<p> + Replace the lines you've found with the following lines: +</p> <pre> -Intent notificationIntent = new Intent(this, MyClass.class); -PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); -notification.contentIntent = contentIntent; + // Sets an activity indicator for an operation of indeterminate length +mBuilder.setProgress(0, 0, false); +// Issues the notification +mNotifyManager.notify(0, mBuilder.build()); </pre> - </li> - - <li>The notification can now be sent as usual: - <pre>mNotificationManager.notify(CUSTOM_VIEW_ID, notification);</pre> - </li> +<p> + The resulting indicator is shown in figure 7: +</p> +<img + id="figure7" + src="{@docRoot}images/ui/notifications/activity_indicator.png" + height="99" + alt="" /> +<p class="img-caption"><strong>Figure 7.</strong> An ongoing activity indicator.</p> + +<!-- ------------------------------------------------------------------------------------------ --> +<!-- ------------------------------------------------------------------------------------------ --> +<!-- ------------------------------------------------------------------------------------------ --> + +<!-- ------------------------------------------------------------------------------------------ --> +<h2 id="CustomNotification">Custom Notification Layouts</h2> +<p> + The notifications framework allows you to define a custom notification layout, which + defines the notification's appearance in a {@link android.widget.RemoteViews} object. + Custom layout notifications are similar to normal notifications, but they're based on a + {@link android.widget.RemoteViews} defined in a XML layout file. +</p> +<p> + To define a custom notification layout, start by instantiating a + {@link android.widget.RemoteViews} object that inflates an XML layout file. Then, + instead of calling methods such as + {@link android.support.v4.app.NotificationCompat.Builder#setContentTitle setContentTitle()}, + call {@link android.support.v4.app.NotificationCompat.Builder#setContent setContent()}. To set + content details in the custom notification, use the methods in + {@link android.widget.RemoteViews} to set the values of the view's children: +</p> +<ol> + <li> + Create an XML layout for the notification in a separate file. You can use any file name + you wish, but you must use the extension <code>.xml</code> + </li> + <li> + In your app, use {@link android.widget.RemoteViews} methods to define your notification's + icons and text. Put this {@link android.widget.RemoteViews} object into your + {@link android.support.v4.app.NotificationCompat.Builder} by calling + {@link android.support.v4.app.NotificationCompat.Builder#setContent setContent()}. Avoid + setting a background {@link android.graphics.drawable.Drawable} on your + {@link android.widget.RemoteViews} object, because your text color may become unreadable. + </li> </ol> - - -<p>The {@link android.widget.RemoteViews} class also includes methods that you can use to easily add -a {@link android.widget.Chronometer} or {@link android.widget.ProgressBar} -in your notification's layout. For more information about creating custom layouts for your -notification, refer to the {@link android.widget.RemoteViews} class reference.</p> - -<p class="caution"><strong>Caution:</strong> -When creating a custom notification layout, you must take special care to ensure that your -custom layout functions properly in different device orientations and resolutions. While this -advice applies to all View layouts created on Android, it is especially important in this case -because your layout real estate is very restricted. So don't make your custom layout too -complex and be sure to test it in various configurations.</p> - - - - +<p> + The {@link android.widget.RemoteViews} class also includes methods that you can use to easily + add a {@link android.widget.Chronometer} or {@link android.widget.ProgressBar} + to your notification's layout. For more information about creating custom layouts for your + notification, refer to the {@link android.widget.RemoteViews} reference documentation. +</p> +<p class="caution"> + <strong>Caution:</strong> When you use a custom notification layout, take special care to + ensure that your custom layout works with different device orientations and resolutions. While + this advice applies to all View layouts, it's especially important for notifications because + the space in the notification drawer is very restricted. Don't make your custom layout too + complex, and be sure to test it in various configurations. +</p> +<!-- ------------------------------------------------------------------------------------------ --> +<h4>Using style resources for custom notification text</h4> +<p> + Always use style resources for the text of a custom notification. The background color of the + notification can vary across different devices and platform versions, and using style resources + helps you account for this. Starting in API level 9, the system defined a style for the + standard notification layout text. If you use the same style in applications that target API + level 9 or higher, you'll ensure that your text is visible against the display background. +</p> diff --git a/docs/html/images/ui/notifications/activity_indicator.png b/docs/html/images/ui/notifications/activity_indicator.png Binary files differnew file mode 100644 index 0000000..e21fae2 --- /dev/null +++ b/docs/html/images/ui/notifications/activity_indicator.png diff --git a/docs/html/images/ui/notifications/bigpicture_notification.png b/docs/html/images/ui/notifications/bigpicture_notification.png Binary files differnew file mode 100644 index 0000000..ced6380 --- /dev/null +++ b/docs/html/images/ui/notifications/bigpicture_notification.png diff --git a/docs/html/images/ui/notifications/bigpicture_notification_callouts.png b/docs/html/images/ui/notifications/bigpicture_notification_callouts.png Binary files differnew file mode 100644 index 0000000..e2d313a --- /dev/null +++ b/docs/html/images/ui/notifications/bigpicture_notification_callouts.png diff --git a/docs/html/images/ui/notifications/bigtext_notification.png b/docs/html/images/ui/notifications/bigtext_notification.png Binary files differnew file mode 100644 index 0000000..cd6e764 --- /dev/null +++ b/docs/html/images/ui/notifications/bigtext_notification.png diff --git a/docs/html/images/ui/notifications/bigtext_notification_callouts.png b/docs/html/images/ui/notifications/bigtext_notification_callouts.png Binary files differnew file mode 100644 index 0000000..4cfa403 --- /dev/null +++ b/docs/html/images/ui/notifications/bigtext_notification_callouts.png diff --git a/docs/html/images/ui/notifications/custom_message.png b/docs/html/images/ui/notifications/custom_message.png Binary files differnew file mode 100755 index 0000000..00b7632 --- /dev/null +++ b/docs/html/images/ui/notifications/custom_message.png diff --git a/docs/html/images/ui/notifications/iconic_notification.png b/docs/html/images/ui/notifications/iconic_notification.png Binary files differnew file mode 100644 index 0000000..4cabfdb --- /dev/null +++ b/docs/html/images/ui/notifications/iconic_notification.png diff --git a/docs/html/images/ui/notifications/inbox_notification.png b/docs/html/images/ui/notifications/inbox_notification.png Binary files differnew file mode 100644 index 0000000..fb182d5 --- /dev/null +++ b/docs/html/images/ui/notifications/inbox_notification.png diff --git a/docs/html/images/ui/notifications/inbox_notification_callouts.png b/docs/html/images/ui/notifications/inbox_notification_callouts.png Binary files differnew file mode 100644 index 0000000..2ec818e --- /dev/null +++ b/docs/html/images/ui/notifications/inbox_notification_callouts.png diff --git a/docs/html/images/ui/notifications/normal_notification.png b/docs/html/images/ui/notifications/normal_notification.png Binary files differnew file mode 100644 index 0000000..3cf0231 --- /dev/null +++ b/docs/html/images/ui/notifications/normal_notification.png diff --git a/docs/html/images/ui/notifications/normal_notification_callouts.png b/docs/html/images/ui/notifications/normal_notification_callouts.png Binary files differnew file mode 100644 index 0000000..db57daf --- /dev/null +++ b/docs/html/images/ui/notifications/normal_notification_callouts.png diff --git a/docs/html/images/ui/notifications/notifications_window.png b/docs/html/images/ui/notifications/notifications_window.png Binary files differnew file mode 100755 index 0000000..0354ee9 --- /dev/null +++ b/docs/html/images/ui/notifications/notifications_window.png diff --git a/docs/html/images/ui/notifications/progress_bar_summary.png b/docs/html/images/ui/notifications/progress_bar_summary.png Binary files differnew file mode 100644 index 0000000..073e697 --- /dev/null +++ b/docs/html/images/ui/notifications/progress_bar_summary.png diff --git a/docs/html/images/ui/notifications/progress_indicator_1.png b/docs/html/images/ui/notifications/progress_indicator_1.png Binary files differnew file mode 100644 index 0000000..f4c2365 --- /dev/null +++ b/docs/html/images/ui/notifications/progress_indicator_1.png diff --git a/docs/html/images/ui/notifications/progress_indicator_2.png b/docs/html/images/ui/notifications/progress_indicator_2.png Binary files differnew file mode 100644 index 0000000..975c90e --- /dev/null +++ b/docs/html/images/ui/notifications/progress_indicator_2.png diff --git a/docs/html/images/ui/notifications/status_bar.png b/docs/html/images/ui/notifications/status_bar.png Binary files differnew file mode 100755 index 0000000..f0240a5 --- /dev/null +++ b/docs/html/images/ui/notifications/status_bar.png diff --git a/docs/html/images/ui/notifications/updated_notification.png b/docs/html/images/ui/notifications/updated_notification.png Binary files differnew file mode 100644 index 0000000..f69fa4b --- /dev/null +++ b/docs/html/images/ui/notifications/updated_notification.png diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index 4604437..6238edb 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -967,7 +967,7 @@ public final class Bitmap implements Parcelable { * @hide */ static public int scaleFromDensity(int size, int sdensity, int tdensity) { - if (sdensity == DENSITY_NONE || sdensity == tdensity) { + if (sdensity == DENSITY_NONE || tdensity == DENSITY_NONE || sdensity == tdensity) { return size; } diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 9b1a892..1460996 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -153,9 +153,9 @@ <skip /> <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"Usuario <xliff:g id="USER">%s</xliff:g>"</string> <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string> - <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Celular <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string> + <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Móvil <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string> <string name="accessibility_quick_settings_battery" msgid="1480931583381408972">"Batería <xliff:g id="STATE">%s</xliff:g>"</string> - <string name="accessibility_quick_settings_airplane" msgid="4196876722090224753">"Modo avión <xliff:g id="STATE">%s</xliff:g>"</string> + <string name="accessibility_quick_settings_airplane" msgid="4196876722090224753">"Modo de avión <xliff:g id="STATE">%s</xliff:g>"</string> <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth <xliff:g id="STATE">%s</xliff:g>"</string> <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Alarma: <xliff:g id="TIME">%s</xliff:g>"</string> <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"Datos de 2G-3G inhabilitados"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 9a7e56d..9f0fbda 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -175,7 +175,7 @@ <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"La pantalla está bloqueada en modo horizontal."</string> <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"La pantalla está bloqueada en modo vertical."</string> <string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string> - <string name="start_dreams" msgid="6170089063982549905">"Activar suspensión"</string> + <string name="start_dreams" msgid="6170089063982549905">"Suspender"</string> <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string> <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Modo avión"</string> <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Cargando (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 58c9dec..468375f 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -203,5 +203,5 @@ <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Độ sáng"</string> <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"TỰ ĐỘNG"</string> <string name="status_bar_help_title" msgid="1199237744086469217">"Thông báo xuất hiện tại đây"</string> - <string name="status_bar_help_text" msgid="7874607155052076323">"Truy cập vào chúng bất kỳ lúc nào bằng cách trượt xuống."\n"Trượt lại xuống để có các điều khiển hệ thống."</string> + <string name="status_bar_help_text" msgid="7874607155052076323">"Truy cập vào chúng bất kỳ lúc nào bằng cách vuốt xuống."\n"Vuốt lại xuống để hiển thị các điều khiển hệ thống."</string> </resources> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index 29b682d..d0323f0 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -204,6 +204,6 @@ <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"無線螢幕分享"</string> <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"亮度"</string> <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自動"</string> - <string name="status_bar_help_title" msgid="1199237744086469217">"通知會顯示在這裡"</string> + <string name="status_bar_help_title" msgid="1199237744086469217">"系統會在這裡顯示通知"</string> <string name="status_bar_help_text" msgid="7874607155052076323">"向下滑動即可隨時存取通知。"\n"再次向下滑動即可使用系統控制項。"</string> </resources> diff --git a/packages/SystemUI/src/com/android/systemui/Somnambulator.java b/packages/SystemUI/src/com/android/systemui/Somnambulator.java index 9356ff2..0dd6d92 100644 --- a/packages/SystemUI/src/com/android/systemui/Somnambulator.java +++ b/packages/SystemUI/src/com/android/systemui/Somnambulator.java @@ -1,4 +1,4 @@ -/*); +/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,38 +18,23 @@ package com.android.systemui; import android.app.Activity; import android.content.Intent; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.os.UserHandle; -import android.provider.Settings; -import android.service.dreams.DreamService; -import android.service.dreams.IDreamManager; -import android.util.Slog; - +import android.service.dreams.Sandman; + +/** + * A simple activity that launches a dream. + * <p> + * Note: This Activity is special. If this class is moved to another package or + * renamed, be sure to update the component name in {@link Sandman}. + * </p> + */ public class Somnambulator extends Activity { - public static final String TAG = "Somnambulator"; - - public static final int DEFAULT_SCREENSAVER_ENABLED = 1; - public static final int DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK = 1; - public Somnambulator() { } - private boolean isScreenSaverEnabled() { - return Settings.Secure.getIntForUser(getContentResolver(), - Settings.Secure.SCREENSAVER_ENABLED, DEFAULT_SCREENSAVER_ENABLED, - UserHandle.USER_CURRENT) != 0; - } - - private boolean isScreenSaverActivatedOnDock() { - return Settings.Secure.getIntForUser(getContentResolver(), - Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK, - DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK, UserHandle.USER_CURRENT) != 0; - } - @Override public void onStart() { super.onStart(); + final Intent launchIntent = getIntent(); final String action = launchIntent.getAction(); if (Intent.ACTION_CREATE_SHORTCUT.equals(action)) { @@ -64,23 +49,12 @@ public class Somnambulator extends Activity { setResult(RESULT_OK, resultIntent); } else { boolean docked = launchIntent.hasCategory(Intent.CATEGORY_DESK_DOCK); - - if (docked && !(isScreenSaverEnabled() && isScreenSaverActivatedOnDock())) { - Slog.i(TAG, "Dreams currently disabled for docks."); + if (docked) { + Sandman.startDreamWhenDockedIfAppropriate(this); } else { - IDreamManager somnambulist = IDreamManager.Stub.asInterface( - ServiceManager.checkService(DreamService.DREAM_SERVICE)); - if (somnambulist != null) { - try { - Slog.v(TAG, "Dreaming on " + (docked ? "dock insertion" : "user request")); - somnambulist.dream(); - } catch (RemoteException e) { - // fine, stay asleep then - } - } + Sandman.startDreamByUserRequest(this); } } finish(); } - } diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java index 2d4eb79..0e456f1 100644 --- a/services/java/com/android/server/UiModeManagerService.java +++ b/services/java/com/android/server/UiModeManagerService.java @@ -37,11 +37,9 @@ import android.os.Handler; import android.os.PowerManager; import android.os.RemoteException; import android.os.ServiceManager; -import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; -import android.service.dreams.DreamService; -import android.service.dreams.IDreamManager; +import android.service.dreams.Sandman; import android.util.Slog; import java.io.FileDescriptor; @@ -59,9 +57,6 @@ final class UiModeManagerService extends IUiModeManager.Stub { private static final boolean ENABLE_LAUNCH_CAR_DOCK_APP = true; private static final boolean ENABLE_LAUNCH_DESK_DOCK_APP = true; - private static final int DEFAULT_SCREENSAVER_ENABLED = 1; - private static final int DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK = 1; - private final Context mContext; private final TwilightService mTwilightService; private final Handler mHandler = new Handler(); @@ -496,18 +491,20 @@ final class UiModeManagerService extends IUiModeManager.Stub { // activity manager take care of both the start and config // change. Intent homeIntent = buildHomeIntent(category); - try { - int result = ActivityManagerNative.getDefault().startActivityWithConfig( - null, homeIntent, null, null, null, 0, 0, - mConfiguration, null, UserHandle.USER_CURRENT); - if (result >= ActivityManager.START_SUCCESS) { - dockAppStarted = true; - } else if (result != ActivityManager.START_INTENT_NOT_RESOLVED) { - Slog.e(TAG, "Could not start dock app: " + homeIntent - + ", startActivityWithConfig result " + result); + if (Sandman.shouldStartDockApp(mContext, homeIntent)) { + try { + int result = ActivityManagerNative.getDefault().startActivityWithConfig( + null, homeIntent, null, null, null, 0, 0, + mConfiguration, null, UserHandle.USER_CURRENT); + if (result >= ActivityManager.START_SUCCESS) { + dockAppStarted = true; + } else if (result != ActivityManager.START_INTENT_NOT_RESOLVED) { + Slog.e(TAG, "Could not start dock app: " + homeIntent + + ", startActivityWithConfig result " + result); + } + } catch (RemoteException ex) { + Slog.e(TAG, "Could not start dock app: " + homeIntent, ex); } - } catch (RemoteException ex) { - Slog.e(TAG, "Could not start dock app: " + homeIntent, ex); } } @@ -515,41 +512,11 @@ final class UiModeManagerService extends IUiModeManager.Stub { sendConfigurationLocked(); // If we did not start a dock app, then start dreaming if supported. - if (category != null && !dockAppStarted - && isScreenSaverEnabledLocked() && isScreenSaverActivatedOnDockLocked()) { - Slog.i(TAG, "Activating dream while docked."); - try { - IDreamManager dreamManagerService = IDreamManager.Stub.asInterface( - ServiceManager.getService(DreamService.DREAM_SERVICE)); - if (dreamManagerService != null && !dreamManagerService.isDreaming()) { - // Wake up. - // The power manager will wake up the system when it starts receiving power - // but there is a race between that happening and the UI mode manager - // starting a dream. We want the system to already be awake - // by the time this happens. Otherwise the dream may not start. - mPowerManager.wakeUp(SystemClock.uptimeMillis()); - - // Dream. - dreamManagerService.dream(); - } - } catch (RemoteException ex) { - Slog.e(TAG, "Could not start dream when docked.", ex); - } + if (category != null && !dockAppStarted) { + Sandman.startDreamWhenDockedIfAppropriate(mContext); } } - private boolean isScreenSaverEnabledLocked() { - return Settings.Secure.getIntForUser(mContext.getContentResolver(), - Settings.Secure.SCREENSAVER_ENABLED, DEFAULT_SCREENSAVER_ENABLED, - UserHandle.USER_CURRENT) != 0; - } - - private boolean isScreenSaverActivatedOnDockLocked() { - return Settings.Secure.getIntForUser(mContext.getContentResolver(), - Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK, - DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK, UserHandle.USER_CURRENT) != 0; - } - private void adjustStatusBarCarModeLocked() { if (mStatusBarManager == null) { mStatusBarManager = (StatusBarManager) diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index b8d7286..f59e30d 100644 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -1835,7 +1835,8 @@ public class PackageManagerService extends IPackageManager.Stub { PackageSetting ps = mSettings.mPackages.get(packageName); if (ps == null) return null; // Note: isEnabledLP() does not apply here - always return info - return PackageParser.generateApplicationInfo(p, flags, ps.readUserState(userId)); + return PackageParser.generateApplicationInfo( + p, flags, ps.readUserState(userId), userId); } if ("android".equals(packageName)||"system".equals(packageName)) { return mAndroidApplication; diff --git a/tests/RenderScriptTests/ImageProcessing2/res/drawable-nodpi/img1600x1067.jpg b/tests/RenderScriptTests/ImageProcessing2/res/drawable-nodpi/img1600x1067.jpg Binary files differnew file mode 100644 index 0000000..05d3ee2 --- /dev/null +++ b/tests/RenderScriptTests/ImageProcessing2/res/drawable-nodpi/img1600x1067.jpg diff --git a/tests/RenderScriptTests/ImageProcessing2/res/drawable-nodpi/img1600x1067b.jpg b/tests/RenderScriptTests/ImageProcessing2/res/drawable-nodpi/img1600x1067b.jpg Binary files differnew file mode 100644 index 0000000..aed0781 --- /dev/null +++ b/tests/RenderScriptTests/ImageProcessing2/res/drawable-nodpi/img1600x1067b.jpg diff --git a/tests/RenderScriptTests/ImageProcessing2/res/layout/main.xml b/tests/RenderScriptTests/ImageProcessing2/res/layout/main.xml index bd56d62..f0a2b92 100644 --- a/tests/RenderScriptTests/ImageProcessing2/res/layout/main.xml +++ b/tests/RenderScriptTests/ImageProcessing2/res/layout/main.xml @@ -54,6 +54,10 @@ android:id="@+id/filterselection" android:layout_width="fill_parent" android:layout_height="wrap_content"/> + <Spinner + android:id="@+id/spinner1" + android:layout_width="fill_parent" + android:layout_height="wrap_content"/> <TextView android:id="@+id/slider1Text" android:layout_width="match_parent" @@ -124,6 +128,11 @@ android:layout_marginRight="10sp" android:layout_width="match_parent" android:layout_height="wrap_content"/> + <Button + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/benchmark_all" + android:onClick="benchmark_all"/> </LinearLayout> </ScrollView> </LinearLayout> diff --git a/tests/RenderScriptTests/ImageProcessing2/res/values/strings.xml b/tests/RenderScriptTests/ImageProcessing2/res/values/strings.xml index cc5cc4d..a7dd165 100644 --- a/tests/RenderScriptTests/ImageProcessing2/res/values/strings.xml +++ b/tests/RenderScriptTests/ImageProcessing2/res/values/strings.xml @@ -29,5 +29,6 @@ <string name="gamma">Gamma</string> <string name="saturation">Saturation</string> <string name="benchmark">Benchmark</string> + <string name="benchmark_all">Benchmark All</string> </resources> diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Blend.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Blend.java new file mode 100644 index 0000000..ac02101 --- /dev/null +++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Blend.java @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2012 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 com.android.rs.image2; + +import java.lang.Math; +import java.lang.Short; + +import android.support.v8.renderscript.*; +import android.util.Log; +import android.widget.SeekBar; +import android.widget.TextView; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.view.View; +import android.widget.Spinner; + +public class Blend extends TestBase { + private ScriptIntrinsicBlend mBlend; + private ScriptC_blend mBlendHelper; + private short image1Alpha = 128; + private short image2Alpha = 128; + + String mIntrinsicNames[]; + + private Allocation image1; + private Allocation image2; + private int currentIntrinsic = 0; + + private AdapterView.OnItemSelectedListener mIntrinsicSpinnerListener = + new AdapterView.OnItemSelectedListener() { + public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) { + currentIntrinsic = pos; + runTest(); + act.updateDisplay(); + } + + public void onNothingSelected(AdapterView parent) { + + } + }; + + public void createTest(android.content.res.Resources res) { + mBlend = ScriptIntrinsicBlend.create(mRS, Element.U8_4(mRS)); + mBlendHelper = new ScriptC_blend(mRS); + mBlendHelper.set_alpha((short)128); + + image1 = Allocation.createTyped(mRS, mInPixelsAllocation.getType()); + image2 = Allocation.createTyped(mRS, mInPixelsAllocation2.getType()); + + mIntrinsicNames = new String[14]; + mIntrinsicNames[0] = "Source"; + mIntrinsicNames[1] = "Destination"; + mIntrinsicNames[2] = "Source Over"; + mIntrinsicNames[3] = "Destination Over"; + mIntrinsicNames[4] = "Source In"; + mIntrinsicNames[5] = "Destination In"; + mIntrinsicNames[6] = "Source Out"; + mIntrinsicNames[7] = "Destination Out"; + mIntrinsicNames[8] = "Source Atop"; + mIntrinsicNames[9] = "Destination Atop"; + mIntrinsicNames[10] = "XOR"; + mIntrinsicNames[11] = "Add"; + mIntrinsicNames[12] = "Subtract"; + mIntrinsicNames[13] = "Multiply"; + } + + public boolean onSpinner1Setup(Spinner s) { + s.setAdapter(new ArrayAdapter<String>( + act, R.layout.spinner_layout, mIntrinsicNames)); + s.setOnItemSelectedListener(mIntrinsicSpinnerListener); + return true; + } + + public boolean onBar1Setup(SeekBar b, TextView t) { + t.setText("Image 1 Alpha"); + b.setMax(255); + b.setProgress(image1Alpha); + return true; + } + + public void onBar1Changed(int progress) { + image1Alpha = (short)progress; + } + + public boolean onBar2Setup(SeekBar b, TextView t) { + t.setText("Image 2 Alpha"); + b.setMax(255); + b.setProgress(image2Alpha); + return true; + } + + public void onBar2Changed(int progress) { + image2Alpha = (short)progress; + } + + public void runTest() { + image1.copy2DRangeFrom(0, 0, mInPixelsAllocation.getType().getX(), mInPixelsAllocation.getType().getY(), mInPixelsAllocation, 0, 0); + image2.copy2DRangeFrom(0, 0, mInPixelsAllocation2.getType().getX(), mInPixelsAllocation2.getType().getY(), mInPixelsAllocation2, 0, 0); + + mBlendHelper.set_alpha(image1Alpha); + mBlendHelper.forEach_setImageAlpha(image1); + + mBlendHelper.set_alpha(image2Alpha); + mBlendHelper.forEach_setImageAlpha(image2); + + switch (currentIntrinsic) { + case 0: + mBlend.forEachSrc(image1, image2); + break; + case 1: + mBlend.forEachDst(image1, image2); + break; + case 2: + mBlend.forEachSrcOver(image1, image2); + break; + case 3: + mBlend.forEachDstOver(image1, image2); + break; + case 4: + mBlend.forEachSrcIn(image1, image2); + break; + case 5: + mBlend.forEachDstIn(image1, image2); + break; + case 6: + mBlend.forEachSrcOut(image1, image2); + break; + case 7: + mBlend.forEachDstOut(image1, image2); + break; + case 8: + mBlend.forEachSrcAtop(image1, image2); + break; + case 9: + mBlend.forEachDstAtop(image1, image2); + break; + case 10: + mBlend.forEachXor(image1, image2); + break; + case 11: + mBlend.forEachAdd(image1, image2); + break; + case 12: + mBlend.forEachSubtract(image1, image2); + break; + case 13: + mBlend.forEachMultiply(image1, image2); + break; + } + + mOutPixelsAllocation.copy2DRangeFrom(0, 0, image2.getType().getX(), image2.getType().getY(), image2, 0, 0); + } + +} diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Blur25.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Blur25.java index be87716..b518b02 100644 --- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Blur25.java +++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Blur25.java @@ -24,37 +24,38 @@ import android.widget.SeekBar; import android.widget.TextView; public class Blur25 extends TestBase { + private boolean mUseIntrinsic = false; + private ScriptIntrinsicBlur mIntrinsic; + private int MAX_RADIUS = 25; private ScriptC_threshold mScript; - private ScriptC_vertical_blur mScriptVBlur; - private ScriptC_horizontal_blur mScriptHBlur; - private int mRadius = MAX_RADIUS; + private float mRadius = MAX_RADIUS; private float mSaturation = 1.0f; private Allocation mScratchPixelsAllocation1; private Allocation mScratchPixelsAllocation2; + public Blur25(boolean useIntrinsic) { + mUseIntrinsic = useIntrinsic; + } + public boolean onBar1Setup(SeekBar b, TextView t) { t.setText("Radius"); b.setProgress(100); return true; } - public boolean onBar2Setup(SeekBar b, TextView t) { - b.setProgress(50); - t.setText("Saturation"); - return true; - } public void onBar1Changed(int progress) { - float fRadius = progress / 100.0f; - fRadius *= (float)(MAX_RADIUS); - mRadius = (int)fRadius; - mScript.set_radius(mRadius); - } - public void onBar2Changed(int progress) { - mSaturation = (float)progress / 50.0f; - mScriptVBlur.invoke_setSaturation(mSaturation); + mRadius = ((float)progress) / 100.0f * MAX_RADIUS; + if (mRadius <= 0.10f) { + mRadius = 0.10f; + } + if (mUseIntrinsic) { + mIntrinsic.setRadius(mRadius); + } else { + mScript.invoke_setRadius((int)mRadius); + } } @@ -62,40 +63,52 @@ public class Blur25 extends TestBase { int width = mInPixelsAllocation.getType().getX(); int height = mInPixelsAllocation.getType().getY(); - Type.Builder tb = new Type.Builder(mRS, Element.F32_4(mRS)); - tb.setX(width); - tb.setY(height); - mScratchPixelsAllocation1 = Allocation.createTyped(mRS, tb.create()); - mScratchPixelsAllocation2 = Allocation.createTyped(mRS, tb.create()); - - mScriptVBlur = new ScriptC_vertical_blur(mRS, res, R.raw.vertical_blur); - mScriptHBlur = new ScriptC_horizontal_blur(mRS, res, R.raw.horizontal_blur); - - mScript = new ScriptC_threshold(mRS, res, R.raw.threshold); - mScript.set_width(width); - mScript.set_height(height); - mScript.set_radius(mRadius); - - mScriptVBlur.invoke_setSaturation(mSaturation); - - mScript.bind_InPixel(mInPixelsAllocation); - mScript.bind_OutPixel(mOutPixelsAllocation); - mScript.bind_ScratchPixel1(mScratchPixelsAllocation1); - mScript.bind_ScratchPixel2(mScratchPixelsAllocation2); - - mScript.set_vBlurScript(mScriptVBlur); - mScript.set_hBlurScript(mScriptHBlur); + if (mUseIntrinsic) { + mIntrinsic = ScriptIntrinsicBlur.create(mRS, Element.U8_4(mRS)); + mIntrinsic.setRadius(MAX_RADIUS); + mIntrinsic.setInput(mInPixelsAllocation); + } else { + + Type.Builder tb = new Type.Builder(mRS, Element.F32_4(mRS)); + tb.setX(width); + tb.setY(height); + mScratchPixelsAllocation1 = Allocation.createTyped(mRS, tb.create()); + mScratchPixelsAllocation2 = Allocation.createTyped(mRS, tb.create()); + + mScript = new ScriptC_threshold(mRS, res, R.raw.threshold); + mScript.set_width(width); + mScript.set_height(height); + mScript.invoke_setRadius(MAX_RADIUS); + + mScript.set_InPixel(mInPixelsAllocation); + mScript.set_ScratchPixel1(mScratchPixelsAllocation1); + mScript.set_ScratchPixel2(mScratchPixelsAllocation2); + } } public void runTest() { - mScript.invoke_filter(); + if (mUseIntrinsic) { + mIntrinsic.forEach(mOutPixelsAllocation); + } else { + mScript.forEach_copyIn(mInPixelsAllocation, mScratchPixelsAllocation1); + mScript.forEach_horz(mScratchPixelsAllocation2); + mScript.forEach_vert(mOutPixelsAllocation); + } } public void setupBenchmark() { - mScript.set_radius(MAX_RADIUS); + if (mUseIntrinsic) { + mIntrinsic.setRadius(MAX_RADIUS); + } else { + mScript.invoke_setRadius(MAX_RADIUS); + } } public void exitBenchmark() { - mScript.set_radius(mRadius); + if (mUseIntrinsic) { + mIntrinsic.setRadius(mRadius); + } else { + mScript.invoke_setRadius((int)mRadius); + } } } diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/ColorMatrix.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/ColorMatrix.java new file mode 100644 index 0000000..3b0f86a --- /dev/null +++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/ColorMatrix.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2012 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 com.android.rs.image2; + +import java.lang.Math; + +import android.support.v8.renderscript.*; +import android.util.Log; + +public class ColorMatrix extends TestBase { + private ScriptC_colormatrix mScript; + private ScriptIntrinsicColorMatrix mIntrinsic; + private boolean mUseIntrinsic; + private boolean mUseGrey; + + public ColorMatrix(boolean useIntrinsic, boolean useGrey) { + mUseIntrinsic = useIntrinsic; + mUseGrey = useGrey; + } + + public void createTest(android.content.res.Resources res) { + Matrix4f m = new Matrix4f(); + m.set(1, 0, 0.2f); + m.set(1, 1, 0.9f); + m.set(1, 2, 0.2f); + + if (mUseIntrinsic) { + mIntrinsic = ScriptIntrinsicColorMatrix.create(mRS, Element.U8_4(mRS)); + if (mUseGrey) { + mIntrinsic.setGreyscale(); + } else { + mIntrinsic.setColorMatrix(m); + } + } else { + mScript = new ScriptC_colormatrix(mRS, res, R.raw.colormatrix); + mScript.invoke_setMatrix(m); + } + } + + public void runTest() { + if (mUseIntrinsic) { + mIntrinsic.forEach(mInPixelsAllocation, mOutPixelsAllocation); + } else { + mScript.forEach_root(mInPixelsAllocation, mOutPixelsAllocation); + } + } + +} diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Convolve3x3.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Convolve3x3.java new file mode 100644 index 0000000..7635e13 --- /dev/null +++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Convolve3x3.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2012 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 com.android.rs.image2; + +import java.lang.Math; + +import android.support.v8.renderscript.*; +import android.util.Log; + +public class Convolve3x3 extends TestBase { + private ScriptC_convolve3x3 mScript; + private ScriptIntrinsicConvolve3x3 mIntrinsic; + + private int mWidth; + private int mHeight; + private boolean mUseIntrinsic; + + public Convolve3x3(boolean useIntrinsic) { + mUseIntrinsic = useIntrinsic; + } + + public void createTest(android.content.res.Resources res) { + mWidth = mInPixelsAllocation.getType().getX(); + mHeight = mInPixelsAllocation.getType().getY(); + + float f[] = new float[9]; + f[0] = 0.f; f[1] = -1.f; f[2] = 0.f; + f[3] = -1.f; f[4] = 5.f; f[5] = -1.f; + f[6] = 0.f; f[7] = -1.f; f[8] = 0.f; + + if (mUseIntrinsic) { + mIntrinsic = ScriptIntrinsicConvolve3x3.create(mRS, Element.U8_4(mRS)); + mIntrinsic.setCoefficients(f); + mIntrinsic.setInput(mInPixelsAllocation); + } else { + mScript = new ScriptC_convolve3x3(mRS, res, R.raw.convolve3x3); + mScript.set_gCoeffs(f); + mScript.set_gIn(mInPixelsAllocation); + mScript.set_gWidth(mWidth); + mScript.set_gHeight(mHeight); + } + } + + public void runTest() { + if (mUseIntrinsic) { + mIntrinsic.forEach(mOutPixelsAllocation); + } else { + mScript.forEach_root(mOutPixelsAllocation); + } + } + +} diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Convolve5x5.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Convolve5x5.java new file mode 100644 index 0000000..d2da3c4 --- /dev/null +++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Convolve5x5.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2012 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 com.android.rs.image2; + +import java.lang.Math; + +import android.support.v8.renderscript.*; +import android.util.Log; + +public class Convolve5x5 extends TestBase { + private ScriptC_convolve5x5 mScript; + private ScriptIntrinsicConvolve5x5 mIntrinsic; + + private int mWidth; + private int mHeight; + private boolean mUseIntrinsic; + + public Convolve5x5(boolean useIntrinsic) { + mUseIntrinsic = useIntrinsic; + } + + public void createTest(android.content.res.Resources res) { + mWidth = mInPixelsAllocation.getType().getX(); + mHeight = mInPixelsAllocation.getType().getY(); + + float f[] = new float[25]; + //f[0] = 0.012f; f[1] = 0.025f; f[2] = 0.031f; f[3] = 0.025f; f[4] = 0.012f; + //f[5] = 0.025f; f[6] = 0.057f; f[7] = 0.075f; f[8] = 0.057f; f[9] = 0.025f; + //f[10]= 0.031f; f[11]= 0.075f; f[12]= 0.095f; f[13]= 0.075f; f[14]= 0.031f; + //f[15]= 0.025f; f[16]= 0.057f; f[17]= 0.075f; f[18]= 0.057f; f[19]= 0.025f; + //f[20]= 0.012f; f[21]= 0.025f; f[22]= 0.031f; f[23]= 0.025f; f[24]= 0.012f; + + //f[0] = 1.f; f[1] = 2.f; f[2] = 0.f; f[3] = -2.f; f[4] = -1.f; + //f[5] = 4.f; f[6] = 8.f; f[7] = 0.f; f[8] = -8.f; f[9] = -4.f; + //f[10]= 6.f; f[11]=12.f; f[12]= 0.f; f[13]=-12.f; f[14]= -6.f; + //f[15]= 4.f; f[16]= 8.f; f[17]= 0.f; f[18]= -8.f; f[19]= -4.f; + //f[20]= 1.f; f[21]= 2.f; f[22]= 0.f; f[23]= -2.f; f[24]= -1.f; + + f[0] = -1.f; f[1] = -3.f; f[2] = -4.f; f[3] = -3.f; f[4] = -1.f; + f[5] = -3.f; f[6] = 0.f; f[7] = 6.f; f[8] = 0.f; f[9] = -3.f; + f[10]= -4.f; f[11]= 6.f; f[12]= 20.f; f[13]= 6.f; f[14]= -4.f; + f[15]= -3.f; f[16]= 0.f; f[17]= 6.f; f[18]= 0.f; f[19]= -3.f; + f[20]= -1.f; f[21]= -3.f; f[22]= -4.f; f[23]= -3.f; f[24]= -1.f; + + if (mUseIntrinsic) { + mIntrinsic = ScriptIntrinsicConvolve5x5.create(mRS, Element.U8_4(mRS)); + mIntrinsic.setCoefficients(f); + mIntrinsic.setInput(mInPixelsAllocation); + } else { + mScript = new ScriptC_convolve5x5(mRS, res, R.raw.convolve5x5); + mScript.set_gCoeffs(f); + mScript.set_gIn(mInPixelsAllocation); + mScript.set_gWidth(mWidth); + mScript.set_gHeight(mHeight); + } + } + + public void runTest() { + if (mUseIntrinsic) { + mIntrinsic.forEach(mOutPixelsAllocation); + } else { + mScript.forEach_root(mOutPixelsAllocation); + } + } + +} diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Copy.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Copy.java new file mode 100644 index 0000000..ef71907 --- /dev/null +++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Copy.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2012 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 com.android.rs.image2; + +import java.lang.Math; + +import android.support.v8.renderscript.*; +import android.util.Log; + +public class Copy extends TestBase { + private ScriptC_copy mScript; + + public void createTest(android.content.res.Resources res) { + mScript = new ScriptC_copy(mRS, res, R.raw.copy); + } + + public void runTest() { + mScript.forEach_root(mInPixelsAllocation, mOutPixelsAllocation); + } + +} diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/CrossProcess.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/CrossProcess.java new file mode 100644 index 0000000..96787d7 --- /dev/null +++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/CrossProcess.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2012 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 com.android.rs.image2; + +import java.lang.Math; + +import android.support.v8.renderscript.*; +import android.util.Log; + +public class CrossProcess extends TestBase { + private ScriptIntrinsicLUT mIntrinsic; + + public void createTest(android.content.res.Resources res) { + mIntrinsic = ScriptIntrinsicLUT.create(mRS, Element.U8_4(mRS)); + for (int ct=0; ct < 256; ct++) { + float f = ((float)ct) / 255.f; + + float r = f; + if (r < 0.5f) { + r = 4.0f * r * r * r; + } else { + r = 1.0f - r; + r = 1.0f - (4.0f * r * r * r); + } + mIntrinsic.setRed(ct, (int)(r * 255.f + 0.5f)); + + float g = f; + if (g < 0.5f) { + g = 2.0f * g * g; + } else { + g = 1.0f - g; + g = 1.0f - (2.0f * g * g); + } + mIntrinsic.setGreen(ct, (int)(g * 255.f + 0.5f)); + + float b = f * 0.5f + 0.25f; + mIntrinsic.setBlue(ct, (int)(b * 255.f + 0.5f)); + } + + } + + public void runTest() { + mIntrinsic.forEach(mInPixelsAllocation, mOutPixelsAllocation); + } + +} diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Fisheye.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Fisheye.java index 995cf9d..97beb88 100644 --- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Fisheye.java +++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Fisheye.java @@ -23,12 +23,16 @@ import android.widget.TextView; public class Fisheye extends TestBase { private ScriptC_fisheye_full mScript_full = null; private ScriptC_fisheye_relaxed mScript_relaxed = null; + private ScriptC_fisheye_approx_full mScript_approx_full = null; + private ScriptC_fisheye_approx_relaxed mScript_approx_relaxed = null; + private final boolean approx; private final boolean relaxed; private float center_x = 0.5f; private float center_y = 0.5f; private float scale = 0.5f; - public Fisheye(boolean relaxed) { + public Fisheye(boolean approx, boolean relaxed) { + this.approx = approx; this.relaxed = relaxed; } @@ -65,7 +69,18 @@ public class Fisheye extends TestBase { } private void do_init() { - if (relaxed) + if (approx) { + if (relaxed) + mScript_approx_relaxed.invoke_init_filter( + mInPixelsAllocation.getType().getX(), + mInPixelsAllocation.getType().getY(), center_x, + center_y, scale); + else + mScript_approx_full.invoke_init_filter( + mInPixelsAllocation.getType().getX(), + mInPixelsAllocation.getType().getY(), center_x, + center_y, scale); + } else if (relaxed) mScript_relaxed.invoke_init_filter( mInPixelsAllocation.getType().getX(), mInPixelsAllocation.getType().getY(), center_x, center_y, @@ -78,7 +93,19 @@ public class Fisheye extends TestBase { } public void createTest(android.content.res.Resources res) { - if (relaxed) { + if (approx) { + if (relaxed) { + mScript_approx_relaxed = new ScriptC_fisheye_approx_relaxed(mRS, + res, R.raw.fisheye_approx_relaxed); + mScript_approx_relaxed.set_in_alloc(mInPixelsAllocation); + mScript_approx_relaxed.set_sampler(Sampler.CLAMP_LINEAR(mRS)); + } else { + mScript_approx_full = new ScriptC_fisheye_approx_full(mRS, res, + R.raw.fisheye_approx_full); + mScript_approx_full.set_in_alloc(mInPixelsAllocation); + mScript_approx_full.set_sampler(Sampler.CLAMP_LINEAR(mRS)); + } + } else if (relaxed) { mScript_relaxed = new ScriptC_fisheye_relaxed(mRS, res, R.raw.fisheye_relaxed); mScript_relaxed.set_in_alloc(mInPixelsAllocation); @@ -93,7 +120,12 @@ public class Fisheye extends TestBase { } public void runTest() { - if (relaxed) + if (approx) { + if (relaxed) + mScript_approx_relaxed.forEach_root(mOutPixelsAllocation); + else + mScript_approx_full.forEach_root(mOutPixelsAllocation); + } else if (relaxed) mScript_relaxed.forEach_root(mOutPixelsAllocation); else mScript_full.forEach_root(mOutPixelsAllocation); diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Grain.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Grain.java index e00edd7..dfd3c32 100644 --- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Grain.java +++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Grain.java @@ -40,19 +40,40 @@ public class Grain extends TestBase { mScript.set_gNoiseStrength(s); } + private int findHighBit(int v) { + int bit = 0; + while (v > 1) { + bit++; + v >>= 1; + } + return bit; + } + + public void createTest(android.content.res.Resources res) { int width = mInPixelsAllocation.getType().getX(); int height = mInPixelsAllocation.getType().getY(); + int noiseW = findHighBit(width); + int noiseH = findHighBit(height); + if (noiseW > 9) { + noiseW = 9; + } + if (noiseH > 9) { + noiseH = 9; + } + noiseW = 1 << noiseW; + noiseH = 1 << noiseH; + Type.Builder tb = new Type.Builder(mRS, Element.U8(mRS)); - tb.setX(width); - tb.setY(height); + tb.setX(noiseW); + tb.setY(noiseH); mNoise = Allocation.createTyped(mRS, tb.create()); mNoise2 = Allocation.createTyped(mRS, tb.create()); mScript = new ScriptC_grain(mRS, res, R.raw.grain); - mScript.set_gWidth(width); - mScript.set_gHeight(height); + mScript.set_gWMask(noiseW - 1); + mScript.set_gHMask(noiseH - 1); mScript.set_gNoiseStrength(0.5f); mScript.set_gBlendSource(mNoise); mScript.set_gNoise(mNoise2); diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/GroupTest.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/GroupTest.java index b9fbb59..a7ceebe 100644 --- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/GroupTest.java +++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/GroupTest.java @@ -22,8 +22,8 @@ import android.support.v8.renderscript.*; import android.util.Log; public class GroupTest extends TestBase { - private ScriptC_convolve3x3 mConvolve; - private ScriptC_colormatrix mMatrix; + private ScriptIntrinsicConvolve3x3 mConvolve; + private ScriptIntrinsicColorMatrix mMatrix; private Allocation mScratchPixelsAllocation1; private ScriptGroup mGroup; @@ -41,20 +41,20 @@ public class GroupTest extends TestBase { mWidth = mInPixelsAllocation.getType().getX(); mHeight = mInPixelsAllocation.getType().getY(); - mConvolve = new ScriptC_convolve3x3(mRS, res, R.raw.convolve3x3); - mMatrix = new ScriptC_colormatrix(mRS, res, R.raw.colormatrix); + mConvolve = ScriptIntrinsicConvolve3x3.create(mRS, Element.U8_4(mRS)); + mMatrix = ScriptIntrinsicColorMatrix.create(mRS, Element.U8_4(mRS)); float f[] = new float[9]; f[0] = 0.f; f[1] = -1.f; f[2] = 0.f; f[3] = -1.f; f[4] = 5.f; f[5] = -1.f; f[6] = 0.f; f[7] = -1.f; f[8] = 0.f; - mConvolve.set_gCoeffs(f); + mConvolve.setCoefficients(f); Matrix4f m = new Matrix4f(); m.set(1, 0, 0.2f); m.set(1, 1, 0.9f); m.set(1, 2, 0.2f); - mMatrix.invoke_setMatrix(m); + mMatrix.setColorMatrix(m); Type.Builder tb = new Type.Builder(mRS, Element.U8_4(mRS)); tb.setX(mWidth); @@ -63,24 +63,23 @@ public class GroupTest extends TestBase { if (mUseNative) { ScriptGroup.Builder b = new ScriptGroup.Builder(mRS); - b.addConnection(connect, mConvolve, mMatrix, null); + b.addKernel(mConvolve.getKernelID()); + b.addKernel(mMatrix.getKernelID()); + b.addConnection(connect, mConvolve.getKernelID(), mMatrix.getKernelID()); mGroup = b.create(); - } else { mScratchPixelsAllocation1 = Allocation.createTyped(mRS, connect); } } public void runTest() { - mConvolve.set_gIn(mInPixelsAllocation); - mConvolve.set_gWidth(mWidth); - mConvolve.set_gHeight(mHeight); + mConvolve.setInput(mInPixelsAllocation); if (mUseNative) { - mGroup.setOutput(mMatrix, mOutPixelsAllocation); + mGroup.setOutput(mMatrix.getKernelID(), mOutPixelsAllocation); mGroup.execute(); } else { - mConvolve.forEach_root(mScratchPixelsAllocation1); - mMatrix.forEach_root(mScratchPixelsAllocation1, mOutPixelsAllocation); + mConvolve.forEach(mScratchPixelsAllocation1); + mMatrix.forEach(mScratchPixelsAllocation1, mOutPixelsAllocation); } } diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/ImageProcessingActivity2.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/ImageProcessingActivity2.java index 9b36da14..227518f 100644 --- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/ImageProcessingActivity2.java +++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/ImageProcessingActivity2.java @@ -34,13 +34,27 @@ import android.view.View; import android.util.Log; import java.lang.Math; +import android.os.Environment; +import android.app.Instrumentation; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + public class ImageProcessingActivity2 extends Activity implements SeekBar.OnSeekBarChangeListener { private final String TAG = "Img"; + private final String RESULT_FILE = "image_processing_result.csv"; + Bitmap mBitmapIn; + Bitmap mBitmapIn2; Bitmap mBitmapOut; String mTestNames[]; + private Spinner mSpinner; private SeekBar mBar1; private SeekBar mBar2; private SeekBar mBar3; @@ -64,6 +78,10 @@ public class ImageProcessingActivity2 extends Activity private TestBase mTest; + public void updateDisplay() { + mTest.updateBitmap(mBitmapOut); + mDisplayView.invalidate(); + } public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (fromUser) { @@ -81,8 +99,7 @@ public class ImageProcessingActivity2 extends Activity } mTest.runTest(); - mTest.updateBitmap(mBitmapOut); - mDisplayView.invalidate(); + updateDisplay(); } } @@ -93,6 +110,9 @@ public class ImageProcessingActivity2 extends Activity } void setupBars() { + mSpinner.setVisibility(View.VISIBLE); + mTest.onSpinner1Setup(mSpinner); + mBar1.setVisibility(View.VISIBLE); mText1.setVisibility(View.VISIBLE); mTest.onBar1Setup(mBar1, mText1); @@ -116,6 +136,9 @@ public class ImageProcessingActivity2 extends Activity void changeTest(int testID) { + if (mTest != null) { + mTest.destroy(); + } switch(testID) { case 0: mTest = new LevelsV4(false, false); @@ -130,58 +153,122 @@ public class ImageProcessingActivity2 extends Activity mTest = new LevelsV4(true, true); break; case 4: - mTest = new Blur25(); + mTest = new Blur25(false); break; case 5: - mTest = new Greyscale(); + mTest = new Blur25(true); break; case 6: - mTest = new Grain(); + mTest = new Greyscale(); break; case 7: - mTest = new Fisheye(false); + mTest = new Grain(); break; case 8: - mTest = new Fisheye(true); + mTest = new Fisheye(false, false); break; case 9: - mTest = new Vignette(false); + mTest = new Fisheye(false, true); break; case 10: - mTest = new Vignette(true); + mTest = new Fisheye(true, false); break; case 11: - mTest = new GroupTest(false); + mTest = new Fisheye(true, true); break; case 12: + mTest = new Vignette(false, false); + break; + case 13: + mTest = new Vignette(false, true); + break; + case 14: + mTest = new Vignette(true, false); + break; + case 15: + mTest = new Vignette(true, true); + break; + case 16: + mTest = new GroupTest(false); + break; + case 17: mTest = new GroupTest(true); break; + case 18: + mTest = new Convolve3x3(false); + break; + case 19: + mTest = new Convolve3x3(true); + break; + case 20: + mTest = new ColorMatrix(false, false); + break; + case 21: + mTest = new ColorMatrix(true, false); + break; + case 22: + mTest = new ColorMatrix(true, true); + break; + case 23: + mTest = new Copy(); + break; + case 24: + mTest = new CrossProcess(); + break; + case 25: + mTest = new Convolve5x5(false); + break; + case 26: + mTest = new Convolve5x5(true); + break; + case 27: + mTest = new Mandelbrot(); + break; + case 28: + mTest = new Blend(); + break; } - mTest.createBaseTest(this, mBitmapIn); + mTest.createBaseTest(this, mBitmapIn, mBitmapIn2); setupBars(); mTest.runTest(); - mTest.updateBitmap(mBitmapOut); - mDisplayView.invalidate(); + updateDisplay(); mBenchmarkResult.setText("Result: not run"); } void setupTests() { - mTestNames = new String[13]; + mTestNames = new String[29]; mTestNames[0] = "Levels Vec3 Relaxed"; mTestNames[1] = "Levels Vec4 Relaxed"; mTestNames[2] = "Levels Vec3 Full"; mTestNames[3] = "Levels Vec4 Full"; mTestNames[4] = "Blur radius 25"; - mTestNames[5] = "Greyscale"; - mTestNames[6] = "Grain"; - mTestNames[7] = "Fisheye Full"; - mTestNames[8] = "Fisheye Relaxed"; - mTestNames[9] = "Vignette Full"; - mTestNames[10] = "Vignette Relaxed"; - mTestNames[11] = "Group Test (emulated)"; - mTestNames[12] = "Group Test (native)"; + mTestNames[5] = "Intrinsic Blur radius 25"; + mTestNames[6] = "Greyscale"; + mTestNames[7] = "Grain"; + mTestNames[8] = "Fisheye Full"; + mTestNames[9] = "Fisheye Relaxed"; + mTestNames[10] = "Fisheye Approximate Full"; + mTestNames[11] = "Fisheye Approximate Relaxed"; + mTestNames[12] = "Vignette Full"; + mTestNames[13] = "Vignette Relaxed"; + mTestNames[14] = "Vignette Approximate Full"; + mTestNames[15] = "Vignette Approximate Relaxed"; + mTestNames[16] = "Group Test (emulated)"; + mTestNames[17] = "Group Test (native)"; + mTestNames[18] = "Convolve 3x3"; + mTestNames[19] = "Intrinsics Convolve 3x3"; + mTestNames[20] = "ColorMatrix"; + mTestNames[21] = "Intrinsics ColorMatrix"; + mTestNames[22] = "Intrinsics ColorMatrix Grey"; + mTestNames[23] = "Copy"; + mTestNames[24] = "CrossProcess (using LUT)"; + mTestNames[25] = "Convolve 5x5"; + mTestNames[26] = "Intrinsics Convolve 5x5"; + mTestNames[27] = "Mandelbrot"; + mTestNames[28] = "Intrinsics Blend"; + mTestSpinner.setAdapter(new ArrayAdapter<String>( this, R.layout.spinner_layout, mTestNames)); } @@ -202,14 +289,17 @@ public class ImageProcessingActivity2 extends Activity super.onCreate(savedInstanceState); setContentView(R.layout.main); - mBitmapIn = loadBitmap(R.drawable.city); - mBitmapOut = loadBitmap(R.drawable.city); + mBitmapIn = loadBitmap(R.drawable.img1600x1067); + mBitmapIn2 = loadBitmap(R.drawable.img1600x1067b); + mBitmapOut = loadBitmap(R.drawable.img1600x1067); mSurfaceView = (SurfaceView) findViewById(R.id.surface); mDisplayView = (ImageView) findViewById(R.id.display); mDisplayView.setImageBitmap(mBitmapOut); + mSpinner = (Spinner) findViewById(R.id.spinner1); + mBar1 = (SeekBar) findViewById(R.id.slider1); mBar2 = (SeekBar) findViewById(R.id.slider2); mBar3 = (SeekBar) findViewById(R.id.slider3); @@ -255,37 +345,69 @@ public class ImageProcessingActivity2 extends Activity // button hook public void benchmark(View v) { - long t = getBenchmark(); + float t = getBenchmark(); //long javaTime = javaFilter(); //mBenchmarkResult.setText("RS: " + t + " ms Java: " + javaTime + " ms"); mBenchmarkResult.setText("Result: " + t + " ms"); + Log.v(TAG, "getBenchmark: Renderscript frame time core ms " + t); + } + + public void benchmark_all(View v) { + // write result into a file + File externalStorage = Environment.getExternalStorageDirectory(); + if (!externalStorage.canWrite()) { + Log.v(TAG, "sdcard is not writable"); + return; + } + File resultFile = new File(externalStorage, RESULT_FILE); + //resultFile.setWritable(true, false); + try { + BufferedWriter rsWriter = new BufferedWriter(new FileWriter(resultFile)); + Log.v(TAG, "Saved results in: " + resultFile.getAbsolutePath()); + for (int i = 0; i < mTestNames.length; i++ ) { + changeTest(i); + float t = getBenchmark(); + String s = new String("" + mTestNames[i] + ", " + t); + rsWriter.write(s + "\n"); + Log.v(TAG, "Test " + s + "ms\n"); + } + rsWriter.close(); + } catch (IOException e) { + Log.v(TAG, "Unable to write result file " + e.getMessage()); + } + changeTest(0); } // For benchmark test - public long getBenchmark() { + public float getBenchmark() { mDoingBenchmark = true; mTest.setupBenchmark(); long result = 0; - Log.v(TAG, "Warming"); - long t = java.lang.System.currentTimeMillis() + 2000; + //Log.v(TAG, "Warming"); + long t = java.lang.System.currentTimeMillis() + 250; do { mTest.runTest(); mTest.finish(); } while (t > java.lang.System.currentTimeMillis()); - Log.v(TAG, "Benchmarking"); + //Log.v(TAG, "Benchmarking"); + int ct = 0; t = java.lang.System.currentTimeMillis(); - mTest.runTest(); - mTest.finish(); + do { + mTest.runTest(); + mTest.finish(); + ct++; + } while ((t+1000) > java.lang.System.currentTimeMillis()); t = java.lang.System.currentTimeMillis() - t; + float ft = (float)t; + ft /= ct; - Log.v(TAG, "getBenchmark: Renderscript frame time core ms " + t); mTest.exitBenchmark(); mDoingBenchmark = false; - return t; + return ft; } } diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Mandelbrot.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Mandelbrot.java new file mode 100644 index 0000000..556d797 --- /dev/null +++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Mandelbrot.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2012 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 com.android.rs.image2; + +import java.lang.Math; + +import android.support.v8.renderscript.*; +import android.util.Log; +import android.widget.SeekBar; +import android.widget.TextView; + +public class Mandelbrot extends TestBase { + private ScriptC_mandelbrot mScript; + + public boolean onBar1Setup(SeekBar b, TextView t) { + t.setText("Iterations"); + b.setProgress(0); + return true; + } + + public void onBar1Changed(int progress) { + int iters = progress * 3 + 50; + mScript.set_gMaxIteration(iters); + } + + public boolean onBar2Setup(SeekBar b, TextView t) { + t.setText("Lower Bound: X"); + b.setProgress(0); + return true; + } + + public void onBar2Changed(int progress) { + float scaleFactor = mScript.get_scaleFactor(); + // allow viewport to be moved by 2x scale factor + float lowerBoundX = -2.f + ((progress / scaleFactor) / 50.f); + mScript.set_lowerBoundX(lowerBoundX); + } + + public boolean onBar3Setup(SeekBar b, TextView t) { + t.setText("Lower Bound: Y"); + b.setProgress(0); + return true; + } + + public void onBar3Changed(int progress) { + float scaleFactor = mScript.get_scaleFactor(); + // allow viewport to be moved by 2x scale factor + float lowerBoundY = -2.f + ((progress / scaleFactor) / 50.f); + mScript.set_lowerBoundY(lowerBoundY); + } + + public boolean onBar4Setup(SeekBar b, TextView t) { + t.setText("Scale Factor"); + b.setProgress(0); + return true; + } + + public void onBar4Changed(int progress) { + float scaleFactor = 4.f - (3.96f * (progress / 100.f)); + mScript.set_scaleFactor(scaleFactor); + } + + public void createTest(android.content.res.Resources res) { + int width = mOutPixelsAllocation.getType().getX(); + int height = mOutPixelsAllocation.getType().getY(); + + mScript = new ScriptC_mandelbrot(mRS, res, R.raw.mandelbrot); + mScript.set_gDimX(width); + mScript.set_gDimY(height); + mScript.set_gMaxIteration(50); + } + + public void runTest() { + mScript.forEach_root(mOutPixelsAllocation); + mRS.finish(); + } + +} + diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/TestBase.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/TestBase.java index 35170af..9df2eff 100644 --- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/TestBase.java +++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/TestBase.java @@ -31,14 +31,18 @@ import android.widget.TextView; import android.view.View; import android.util.Log; import java.lang.Math; +import android.widget.Spinner; public class TestBase { protected final String TAG = "Img"; protected RenderScript mRS; protected Allocation mInPixelsAllocation; + protected Allocation mInPixelsAllocation2; protected Allocation mOutPixelsAllocation; + protected ImageProcessingActivity2 act; + // Override to use UI elements public void onBar1Changed(int progress) { } @@ -79,11 +83,20 @@ public class TestBase { return false; } - public final void createBaseTest(ImageProcessingActivity2 act, Bitmap b) { + public boolean onSpinner1Setup(Spinner s) { + s.setVisibility(View.INVISIBLE); + return false; + } + + public final void createBaseTest(ImageProcessingActivity2 ipact, Bitmap b, Bitmap b2) { + act = ipact; mRS = RenderScript.create(act); mInPixelsAllocation = Allocation.createFromBitmap(mRS, b, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT); + mInPixelsAllocation2 = Allocation.createFromBitmap(mRS, b2, + Allocation.MipmapControl.MIPMAP_NONE, + Allocation.USAGE_SCRIPT); mOutPixelsAllocation = Allocation.createFromBitmap(mRS, b, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT); @@ -103,6 +116,10 @@ public class TestBase { mRS.finish(); } + public void destroy() { + mRS.destroy(); + } + public void updateBitmap(Bitmap b) { mOutPixelsAllocation.copyTo(b); } diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Vignette.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Vignette.java index fc69eba..8618d5a 100644 --- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Vignette.java +++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Vignette.java @@ -23,6 +23,9 @@ import android.widget.TextView; public class Vignette extends TestBase { private ScriptC_vignette_full mScript_full = null; private ScriptC_vignette_relaxed mScript_relaxed = null; + private ScriptC_vignette_approx_full mScript_approx_full = null; + private ScriptC_vignette_approx_relaxed mScript_approx_relaxed = null; + private final boolean approx; private final boolean relaxed; private float center_x = 0.5f; private float center_y = 0.5f; @@ -30,7 +33,8 @@ public class Vignette extends TestBase { private float shade = 0.5f; private float slope = 20.0f; - public Vignette(boolean relaxed) { + public Vignette(boolean approx, boolean relaxed) { + this.approx = approx; this.relaxed = relaxed; } @@ -87,7 +91,18 @@ public class Vignette extends TestBase { } private void do_init() { - if (relaxed) + if (approx) { + if (relaxed) + mScript_approx_relaxed.invoke_init_vignette( + mInPixelsAllocation.getType().getX(), + mInPixelsAllocation.getType().getY(), center_x, + center_y, scale, shade, slope); + else + mScript_approx_full.invoke_init_vignette( + mInPixelsAllocation.getType().getX(), + mInPixelsAllocation.getType().getY(), center_x, + center_y, scale, shade, slope); + } else if (relaxed) mScript_relaxed.invoke_init_vignette( mInPixelsAllocation.getType().getX(), mInPixelsAllocation.getType().getY(), center_x, center_y, @@ -100,21 +115,36 @@ public class Vignette extends TestBase { } public void createTest(android.content.res.Resources res) { - if (relaxed) { + if (approx) { + if (relaxed) + mScript_approx_relaxed = new ScriptC_vignette_approx_relaxed( + mRS, res, R.raw.vignette_approx_relaxed); + else + mScript_approx_full = new ScriptC_vignette_approx_full( + mRS, res, R.raw.vignette_approx_full); + } else if (relaxed) mScript_relaxed = new ScriptC_vignette_relaxed(mRS, res, R.raw.vignette_relaxed); - } else { + else mScript_full = new ScriptC_vignette_full(mRS, res, R.raw.vignette_full); - } do_init(); } public void runTest() { - if (relaxed) - mScript_relaxed.forEach_root(mInPixelsAllocation, mOutPixelsAllocation); + if (approx) { + if (relaxed) + mScript_approx_relaxed.forEach_root(mInPixelsAllocation, + mOutPixelsAllocation); + else + mScript_approx_full.forEach_root(mInPixelsAllocation, + mOutPixelsAllocation); + } else if (relaxed) + mScript_relaxed.forEach_root(mInPixelsAllocation, + mOutPixelsAllocation); else - mScript_full.forEach_root(mInPixelsAllocation, mOutPixelsAllocation); + mScript_full.forEach_root(mInPixelsAllocation, + mOutPixelsAllocation); } } diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/blend.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/blend.rs new file mode 100644 index 0000000..4d90725 --- /dev/null +++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/blend.rs @@ -0,0 +1,24 @@ +// Copyright (C) 2011 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. + +#pragma version(1) +#pragma rs java_package_name(com.android.rs.image2) + +uchar alpha = 0x0; + +void setImageAlpha(uchar4 *v_out, uint32_t x, uint32_t y) { + v_out->rgba = convert_uchar4((convert_uint4(v_out->rgba) * alpha) >> (uint4)8); + v_out->a = alpha; +} + diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/convolve5x5.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/convolve5x5.rs new file mode 100644 index 0000000..b110b88 --- /dev/null +++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/convolve5x5.rs @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2012 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. + */ + +#pragma version(1) +#pragma rs java_package_name(com.android.rs.image2) +#pragma rs_fp_relaxed + +int32_t gWidth; +int32_t gHeight; +rs_allocation gIn; + +float gCoeffs[25]; + +void root(uchar4 *out, uint32_t x, uint32_t y) { + uint32_t x0 = max((int32_t)x-2, 0); + uint32_t x1 = max((int32_t)x-1, 0); + uint32_t x2 = x; + uint32_t x3 = min((int32_t)x+1, gWidth-1); + uint32_t x4 = min((int32_t)x+2, gWidth-1); + + uint32_t y0 = max((int32_t)y-2, 0); + uint32_t y1 = max((int32_t)y-1, 0); + uint32_t y2 = y; + uint32_t y3 = min((int32_t)y+1, gHeight-1); + uint32_t y4 = min((int32_t)y+2, gHeight-1); + + float4 p0 = convert_float4(rsGetElementAt_uchar4(gIn, x0, y0)) * gCoeffs[0] + + convert_float4(rsGetElementAt_uchar4(gIn, x1, y0)) * gCoeffs[1] + + convert_float4(rsGetElementAt_uchar4(gIn, x2, y0)) * gCoeffs[2] + + convert_float4(rsGetElementAt_uchar4(gIn, x3, y0)) * gCoeffs[3] + + convert_float4(rsGetElementAt_uchar4(gIn, x4, y0)) * gCoeffs[4]; + + float4 p1 = convert_float4(rsGetElementAt_uchar4(gIn, x0, y1)) * gCoeffs[5] + + convert_float4(rsGetElementAt_uchar4(gIn, x1, y1)) * gCoeffs[6] + + convert_float4(rsGetElementAt_uchar4(gIn, x2, y1)) * gCoeffs[7] + + convert_float4(rsGetElementAt_uchar4(gIn, x3, y1)) * gCoeffs[8] + + convert_float4(rsGetElementAt_uchar4(gIn, x4, y1)) * gCoeffs[9]; + + float4 p2 = convert_float4(rsGetElementAt_uchar4(gIn, x0, y2)) * gCoeffs[10] + + convert_float4(rsGetElementAt_uchar4(gIn, x1, y2)) * gCoeffs[11] + + convert_float4(rsGetElementAt_uchar4(gIn, x2, y2)) * gCoeffs[12] + + convert_float4(rsGetElementAt_uchar4(gIn, x3, y2)) * gCoeffs[13] + + convert_float4(rsGetElementAt_uchar4(gIn, x4, y2)) * gCoeffs[14]; + + float4 p3 = convert_float4(rsGetElementAt_uchar4(gIn, x0, y3)) * gCoeffs[15] + + convert_float4(rsGetElementAt_uchar4(gIn, x1, y3)) * gCoeffs[16] + + convert_float4(rsGetElementAt_uchar4(gIn, x2, y3)) * gCoeffs[17] + + convert_float4(rsGetElementAt_uchar4(gIn, x3, y3)) * gCoeffs[18] + + convert_float4(rsGetElementAt_uchar4(gIn, x4, y3)) * gCoeffs[19]; + + float4 p4 = convert_float4(rsGetElementAt_uchar4(gIn, x0, y4)) * gCoeffs[20] + + convert_float4(rsGetElementAt_uchar4(gIn, x1, y4)) * gCoeffs[21] + + convert_float4(rsGetElementAt_uchar4(gIn, x2, y4)) * gCoeffs[22] + + convert_float4(rsGetElementAt_uchar4(gIn, x3, y4)) * gCoeffs[23] + + convert_float4(rsGetElementAt_uchar4(gIn, x4, y4)) * gCoeffs[24]; + + p0 = clamp(p0 + p1 + p2 + p3 + p4, 0.f, 255.f); + *out = convert_uchar4(p0); +} + + diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/copy.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/copy.rs new file mode 100644 index 0000000..31e4241 --- /dev/null +++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/copy.rs @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2012 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. + */ + +#pragma version(1) +#pragma rs java_package_name(com.android.rs.image2) + +void root(const uchar4 *v_in, uchar4 *v_out) { + *v_out = *v_in; +} + + diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye.rsh b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye.rsh index 4dcfc1d..3809912 100644 --- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye.rsh +++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye.rsh @@ -17,46 +17,41 @@ rs_allocation in_alloc; rs_sampler sampler; -static float2 center, dimensions; -static float2 scale; -static float alpha; -static float radius2; -static float factor; - -void init_filter(uint32_t dim_x, uint32_t dim_y, float focus_x, float focus_y, float k) { - center.x = focus_x; - center.y = focus_y; - dimensions.x = (float)dim_x; - dimensions.y = (float)dim_y; +static float2 center, neg_center, inv_dimensions, axis_scale; +static float alpha, radius2, factor; +void init_filter(uint32_t dim_x, uint32_t dim_y, float center_x, float center_y, float k) { + center.x = center_x; + center.y = center_y; + neg_center = -center; + inv_dimensions.x = 1.f / (float)dim_x; + inv_dimensions.y = 1.f / (float)dim_y; alpha = k * 2.0 + 0.75; - float bound2 = 0.25; - if (dim_x > dim_y) { - scale.x = 1.0; - scale.y = dimensions.y / dimensions.x; - bound2 *= (scale.y*scale.y + 1); - } else { - scale.x = dimensions.x / dimensions.y; - scale.y = 1.0; - bound2 *= (scale.x*scale.x + 1); - } + + axis_scale = (float2)1.f; + if (dim_x > dim_y) + axis_scale.y = (float)dim_y / (float)dim_x; + else + axis_scale.x = (float)dim_x / (float)dim_y; + + const float bound2 = 0.25 * (axis_scale.x*axis_scale.x + axis_scale.y*axis_scale.y); const float bound = sqrt(bound2); const float radius = 1.15 * bound; radius2 = radius*radius; - const float max_radian = 0.5f * M_PI - atan(alpha / bound * sqrt(radius2 - bound2)); + const float max_radian = M_PI_2 - atan(alpha / bound * sqrt(radius2 - bound2)); factor = bound / max_radian; } void root(uchar4 *out, uint32_t x, uint32_t y) { // Convert x and y to floating point coordinates with center as origin - float2 coord; - coord.x = (float)x / dimensions.x; - coord.y = (float)y / dimensions.y; - coord -= center; - const float dist = length(scale * coord); - const float radian = M_PI_2 - atan((alpha * sqrt(radius2 - dist * dist)) / dist); - const float scalar = radian * factor / dist; - const float2 new_coord = coord * scalar + center; + const float2 inCoord = {(float)x, (float)y}; + const float2 coord = mad(inCoord, inv_dimensions, neg_center); + const float2 scaledCoord = axis_scale * coord; + const float dist2 = scaledCoord.x*scaledCoord.x + scaledCoord.y*scaledCoord.y; + const float inv_dist = rsqrt(dist2); + const float radian = M_PI_2 - atan((alpha * sqrt(radius2 - dist2)) * inv_dist); + const float scalar = radian * factor * inv_dist; + const float2 new_coord = mad(coord, scalar, center); const float4 fout = rsSample(in_alloc, sampler, new_coord); *out = rsPackColorTo8888(fout); } diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye_approx.rsh b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye_approx.rsh new file mode 100644 index 0000000..08b4126 --- /dev/null +++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye_approx.rsh @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2012 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. + */ + +rs_allocation in_alloc; +rs_sampler sampler; + +static float2 center, neg_center, inv_dimensions, axis_scale; +static float alpha, radius2, factor; + +void init_filter(uint32_t dim_x, uint32_t dim_y, float center_x, float center_y, float k) { + center.x = center_x; + center.y = center_y; + neg_center = -center; + inv_dimensions.x = 1.f / (float)dim_x; + inv_dimensions.y = 1.f / (float)dim_y; + alpha = k * 2.0 + 0.75; + + axis_scale = (float2)1.f; + if (dim_x > dim_y) + axis_scale.y = (float)dim_y / (float)dim_x; + else + axis_scale.x = (float)dim_x / (float)dim_y; + + const float bound2 = 0.25 * (axis_scale.x*axis_scale.x + axis_scale.y*axis_scale.y); + const float bound = sqrt(bound2); + const float radius = 1.15 * bound; + radius2 = radius*radius; + const float max_radian = M_PI_2 - atan(alpha / bound * sqrt(radius2 - bound2)); + factor = bound / max_radian; +} + +void root(uchar4 *out, uint32_t x, uint32_t y) { + // Convert x and y to floating point coordinates with center as origin + const float2 inCoord = {(float)x, (float)y}; + const float2 coord = mad(inCoord, inv_dimensions, neg_center); + const float2 scaledCoord = axis_scale * coord; + const float dist2 = scaledCoord.x*scaledCoord.x + scaledCoord.y*scaledCoord.y; + const float inv_dist = half_rsqrt(dist2); + const float radian = M_PI_2 - atan((alpha * half_sqrt(radius2 - dist2)) * inv_dist); + const float scalar = radian * factor * inv_dist; + const float2 new_coord = mad(coord, scalar, center); + const float4 fout = rsSample(in_alloc, sampler, new_coord); + *out = rsPackColorTo8888(fout); +} + diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye_approx_full.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye_approx_full.rs new file mode 100644 index 0000000..cce42f9 --- /dev/null +++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye_approx_full.rs @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2012 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. + */ + +#pragma version(1) +#pragma rs java_package_name(com.android.rs.image2) + +#include "fisheye_approx.rsh" + diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye_approx_relaxed.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye_approx_relaxed.rs new file mode 100644 index 0000000..64d27ed --- /dev/null +++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye_approx_relaxed.rs @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2012 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. + */ + +#pragma version(1) +#pragma rs java_package_name(com.android.rs.image2) +#pragma rs_fp_relaxed + +#include "fisheye_approx.rsh" + diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/grain.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/grain.rs index 75f4021..44320a5 100644 --- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/grain.rs +++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/grain.rs @@ -38,25 +38,25 @@ void genRand(uchar *out) { * 1 2 1 */ -int32_t gWidth; -int32_t gHeight; +int32_t gWMask; +int32_t gHMask; rs_allocation gBlendSource; void blend9(uchar *out, uint32_t x, uint32_t y) { - uint32_t x1 = min(x+1, (uint32_t)gWidth); - uint32_t x2 = max(x-1, (uint32_t)0); - uint32_t y1 = min(y+1, (uint32_t)gHeight); - uint32_t y2 = max(y-1, (uint32_t)0); + uint32_t x1 = (x-1) & gWMask; + uint32_t x2 = (x+1) & gWMask; + uint32_t y1 = (y-1) & gHMask; + uint32_t y2 = (y+1) & gHMask; - uint p00 = 56 * ((uchar *)rsGetElementAt(gBlendSource, x1, y1))[0]; - uint p01 = 114 * ((uchar *)rsGetElementAt(gBlendSource, x, y1))[0]; - uint p02 = 56 * ((uchar *)rsGetElementAt(gBlendSource, x2, y1))[0]; - uint p10 = 114 * ((uchar *)rsGetElementAt(gBlendSource, x1, y))[0]; - uint p11 = 230 * ((uchar *)rsGetElementAt(gBlendSource, x, y))[0]; - uint p12 = 114 * ((uchar *)rsGetElementAt(gBlendSource, x2, y))[0]; - uint p20 = 56 * ((uchar *)rsGetElementAt(gBlendSource, x1, y2))[0]; - uint p21 = 114 * ((uchar *)rsGetElementAt(gBlendSource, x, y2))[0]; - uint p22 = 56 * ((uchar *)rsGetElementAt(gBlendSource, x2, y2))[0]; + uint p00 = 56 * rsGetElementAt_uchar(gBlendSource, x1, y1); + uint p01 = 114 * rsGetElementAt_uchar(gBlendSource, x, y1); + uint p02 = 56 * rsGetElementAt_uchar(gBlendSource, x2, y1); + uint p10 = 114 * rsGetElementAt_uchar(gBlendSource, x1, y); + uint p11 = 230 * rsGetElementAt_uchar(gBlendSource, x, y); + uint p12 = 114 * rsGetElementAt_uchar(gBlendSource, x2, y); + uint p20 = 56 * rsGetElementAt_uchar(gBlendSource, x1, y2); + uint p21 = 114 * rsGetElementAt_uchar(gBlendSource, x, y2); + uint p22 = 56 * rsGetElementAt_uchar(gBlendSource, x2, y2); p00 += p01; p02 += p10; @@ -69,7 +69,8 @@ void blend9(uchar *out, uint32_t x, uint32_t y) { p20 += p22; p20 += p02; - *out = (uchar)(p20 >> 10); + p20 = min(p20 >> 10, (uint)255); + *out = (uchar)p20; } float gNoiseStrength; @@ -77,7 +78,7 @@ float gNoiseStrength; rs_allocation gNoise; void root(const uchar4 *in, uchar4 *out, uint32_t x, uint32_t y) { float4 ip = convert_float4(*in); - float pnoise = (float) ((uchar *)rsGetElementAt(gNoise, x, y))[0]; + float pnoise = (float) rsGetElementAt_uchar(gNoise, x & gWMask, y & gHMask); float energy_level = ip.r + ip.g + ip.b; float energy_mask = (28.f - sqrt(energy_level)) * 0.03571f; diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/horizontal_blur.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/horizontal_blur.rs deleted file mode 100644 index ee83496..0000000 --- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/horizontal_blur.rs +++ /dev/null @@ -1,28 +0,0 @@ -#pragma version(1) -#pragma rs_fp_relaxed - -#include "ip.rsh" - -void root(float4 *out, const void *usrData, uint32_t x, uint32_t y) { - const FilterStruct *fs = (const FilterStruct *)usrData; - float3 blurredPixel = 0; - const float *gPtr = fs->gaussian; - if ((x > fs->radius) && (x < (fs->width - fs->radius))) { - for (int r = -fs->radius; r <= fs->radius; r ++) { - const float4 *i = (const float4 *)rsGetElementAt(fs->ain, x + r, y); - blurredPixel += i->xyz * gPtr[0]; - gPtr++; - } - } else { - for (int r = -fs->radius; r <= fs->radius; r ++) { - // Stepping left and right away from the pixel - int validX = rsClamp((int)x + r, (int)0, (int)(fs->width - 1)); - const float4 *i = (const float4 *)rsGetElementAt(fs->ain, validX, y); - blurredPixel += i->xyz * gPtr[0]; - gPtr++; - } - } - - out->xyz = blurredPixel; -} - diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/ip.rsh b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/ip.rsh deleted file mode 100644 index 0cdf9e1..0000000 --- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/ip.rsh +++ /dev/null @@ -1,15 +0,0 @@ -#pragma rs java_package_name(com.android.rs.image2) - -#define MAX_RADIUS 25 - -typedef struct FilterStruct_s { - rs_allocation ain; - - float *gaussian; //[MAX_RADIUS * 2 + 1]; - int height; - int width; - int radius; - -} FilterStruct; - - diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/mandelbrot.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/mandelbrot.rs new file mode 100644 index 0000000..55e5304 --- /dev/null +++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/mandelbrot.rs @@ -0,0 +1,56 @@ +// Copyright (C) 2011 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. + +#pragma version(1) +#pragma rs java_package_name(com.android.rs.image2) + +uint32_t gMaxIteration = 500; +uint32_t gDimX = 1024; +uint32_t gDimY = 1024; + +float lowerBoundX = -2.f; +float lowerBoundY = -2.f; +float scaleFactor = 4.f; + +void root(uchar4 *v_out, uint32_t x, uint32_t y) { + float2 p; + p.x = lowerBoundX + ((float)x / gDimX) * scaleFactor; + p.y = lowerBoundY + ((float)y / gDimY) * scaleFactor; + + float2 t = 0; + float2 t2 = t * t; + int iter = 0; + while((t2.x + t2.y < 4.f) && (iter < gMaxIteration)) { + float xtemp = t2.x - t2.y + p.x; + t.y = 2 * t.x * t.y + p.y; + t.x = xtemp; + iter++; + t2 = t * t; + } + + if(iter >= gMaxIteration) { + // write a non-transparent black pixel + *v_out = (uchar4){0, 0, 0, 0xff}; + } else { + float mi3 = gMaxIteration / 3.; + if (iter <= (gMaxIteration / 3)) + *v_out = (uchar4){0xff * (iter / mi3), 0, 0, 0xff}; + else if (iter <= (((gMaxIteration / 3) * 2))) + *v_out = (uchar4){0xff - (0xff * ((iter - mi3) / mi3)), + (0xff * ((iter - mi3) / mi3)), 0, 0xff}; + else + *v_out = (uchar4){0, 0xff - (0xff * ((iter - (mi3 * 2)) / mi3)), + (0xff * ((iter - (mi3 * 2)) / mi3)), 0xff}; + } +} diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/threshold.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/threshold.rs index 77cd5be..9ef4898 100644 --- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/threshold.rs +++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/threshold.rs @@ -1,26 +1,23 @@ #pragma version(1) +#pragma rs java_package_name(com.android.rs.image2) +#pragma rs_fp_relaxed -#include "ip.rsh" int height; int width; -int radius; +static int radius; -uchar4 * InPixel; -uchar4 * OutPixel; -float4 * ScratchPixel1; -float4 * ScratchPixel2; +rs_allocation InPixel; +rs_allocation ScratchPixel1; +rs_allocation ScratchPixel2; -rs_script vBlurScript; -rs_script hBlurScript; - -const int CMD_FINISHED = 1; +const int MAX_RADIUS = 25; // Store our coefficients here static float gaussian[MAX_RADIUS * 2 + 1]; - -static void computeGaussianWeights() { +void setRadius(int rad) { + radius = rad; // Compute gaussian weights for the blur // e is the euler's number float e = 2.718281828459045f; @@ -45,8 +42,7 @@ static void computeGaussianWeights() { float normalizeFactor = 0.0f; float floatR = 0.0f; - int r; - for (r = -radius; r <= radius; r ++) { + for (int r = -radius; r <= radius; r ++) { floatR = (float)r; gaussian[r + radius] = coeff1 * pow(e, floatR * floatR * coeff2); normalizeFactor += gaussian[r + radius]; @@ -54,40 +50,57 @@ static void computeGaussianWeights() { //Now we need to normalize the weights because all our coefficients need to add up to one normalizeFactor = 1.0f / normalizeFactor; - for (r = -radius; r <= radius; r ++) { + for (int r = -radius; r <= radius; r ++) { floatR = (float)r; gaussian[r + radius] *= normalizeFactor; } } +void copyIn(const uchar4 *in, float4 *out) { + *out = convert_float4(*in); +} -static void copyInput() { - rs_allocation ain; - ain = rsGetAllocation(InPixel); - uint32_t dimx = rsAllocationGetDimX(ain); - uint32_t dimy = rsAllocationGetDimY(ain); - for (uint32_t y = 0; y < dimy; y++) { - for (uint32_t x = 0; x < dimx; x++) { - ScratchPixel1[x + y * dimx] = convert_float4(InPixel[x + y * dimx]); +void vert(uchar4 *out, uint32_t x, uint32_t y) { + float3 blurredPixel = 0; + const float *gPtr = gaussian; + if ((y > radius) && (y < (height - radius))) { + for (int r = -radius; r <= radius; r ++) { + const float4 *i = (const float4 *)rsGetElementAt(ScratchPixel2, x, y + r); + blurredPixel += i->xyz * gPtr[0]; + gPtr++; + } + } else { + for (int r = -radius; r <= radius; r ++) { + int validH = rsClamp((int)y + r, (int)0, (int)(height - 1)); + const float4 *i = (const float4 *)rsGetElementAt(ScratchPixel2, x, validH); + blurredPixel += i->xyz * gPtr[0]; + gPtr++; } } -} -void filter() { - copyInput(); - computeGaussianWeights(); - - FilterStruct fs; - fs.gaussian = gaussian; - fs.width = width; - fs.height = height; - fs.radius = radius; + out->xyz = convert_uchar3(clamp(blurredPixel, 0.f, 255.f)); + out->w = 0xff; +} - fs.ain = rsGetAllocation(ScratchPixel1); - rsForEach(hBlurScript, fs.ain, rsGetAllocation(ScratchPixel2), &fs, sizeof(fs)); +void horz(float4 *out, uint32_t x, uint32_t y) { + float3 blurredPixel = 0; + const float *gPtr = gaussian; + if ((x > radius) && (x < (width - radius))) { + for (int r = -radius; r <= radius; r ++) { + const float4 *i = (const float4 *)rsGetElementAt(ScratchPixel1, x + r, y); + blurredPixel += i->xyz * gPtr[0]; + gPtr++; + } + } else { + for (int r = -radius; r <= radius; r ++) { + // Stepping left and right away from the pixel + int validX = rsClamp((int)x + r, (int)0, (int)(width - 1)); + const float4 *i = (const float4 *)rsGetElementAt(ScratchPixel1, validX, y); + blurredPixel += i->xyz * gPtr[0]; + gPtr++; + } + } - fs.ain = rsGetAllocation(ScratchPixel2); - rsForEach(vBlurScript, fs.ain, rsGetAllocation(OutPixel), &fs, sizeof(fs)); - //rsSendToClientBlocking(CMD_FINISHED); + out->xyz = blurredPixel; } diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vertical_blur.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vertical_blur.rs deleted file mode 100644 index 60fd71b..0000000 --- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vertical_blur.rs +++ /dev/null @@ -1,59 +0,0 @@ -#pragma version(1) -#pragma rs_fp_relaxed - -#include "ip.rsh" - -static float saturation; -static rs_matrix3x3 colorMat; - -void setSaturation(float sat) { - saturation = sat; - - // Saturation - // Linear weights - //float rWeight = 0.3086f; - //float gWeight = 0.6094f; - //float bWeight = 0.0820f; - - // Gamma 2.2 weights (we haven't converted our image to linear space yet for perf reasons) - float rWeight = 0.299f; - float gWeight = 0.587f; - float bWeight = 0.114f; - - float oneMinusS = 1.0f - saturation; - rsMatrixSet(&colorMat, 0, 0, oneMinusS * rWeight + saturation); - rsMatrixSet(&colorMat, 0, 1, oneMinusS * rWeight); - rsMatrixSet(&colorMat, 0, 2, oneMinusS * rWeight); - rsMatrixSet(&colorMat, 1, 0, oneMinusS * gWeight); - rsMatrixSet(&colorMat, 1, 1, oneMinusS * gWeight + saturation); - rsMatrixSet(&colorMat, 1, 2, oneMinusS * gWeight); - rsMatrixSet(&colorMat, 2, 0, oneMinusS * bWeight); - rsMatrixSet(&colorMat, 2, 1, oneMinusS * bWeight); - rsMatrixSet(&colorMat, 2, 2, oneMinusS * bWeight + saturation); -} - -void root(uchar4 *out, const void *usrData, uint32_t x, uint32_t y) { - const FilterStruct *fs = (const FilterStruct *)usrData; - float3 blurredPixel = 0; - const float *gPtr = fs->gaussian; - if ((y > fs->radius) && (y < (fs->height - fs->radius))) { - for (int r = -fs->radius; r <= fs->radius; r ++) { - const float4 *i = (const float4 *)rsGetElementAt(fs->ain, x, y + r); - blurredPixel += i->xyz * gPtr[0]; - gPtr++; - } - } else { - for (int r = -fs->radius; r <= fs->radius; r ++) { - int validH = rsClamp((int)y + r, (int)0, (int)(fs->height - 1)); - const float4 *i = (const float4 *)rsGetElementAt(fs->ain, x, validH); - blurredPixel += i->xyz * gPtr[0]; - gPtr++; - } - } - - float3 temp = rsMatrixMultiply(&colorMat, blurredPixel); - temp = clamp(temp, 0.f, 255.f); - out->xyz = convert_uchar3(temp); - out->w = 0xff; -} - diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette_approx.rsh b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette_approx.rsh new file mode 100644 index 0000000..7f7bdcf --- /dev/null +++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette_approx.rsh @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2012 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. + */ + +static float2 neg_center, axis_scale, inv_dimensions; +static float sloped_neg_range, sloped_inv_max_dist, shade, opp_shade; + +void init_vignette(uint32_t dim_x, uint32_t dim_y, float center_x, float center_y, + float desired_scale, float desired_shade, float desired_slope) { + + neg_center.x = -center_x; + neg_center.y = -center_y; + inv_dimensions.x = 1.f / (float)dim_x; + inv_dimensions.y = 1.f / (float)dim_y; + + axis_scale = (float2)1.f; + if (dim_x > dim_y) + axis_scale.y = (float)dim_y / (float)dim_x; + else + axis_scale.x = (float)dim_x / (float)dim_y; + + const float max_dist = 0.5 * length(axis_scale); + sloped_inv_max_dist = desired_slope * 1.f/max_dist; + + // Range needs to be between 1.3 to 0.6. When scale is zero then range is + // 1.3 which means no vignette at all because the luminousity difference is + // less than 1/256. Expect input scale to be between 0.0 and 1.0. + const float neg_range = 0.7*sqrt(desired_scale) - 1.3; + sloped_neg_range = exp(neg_range * desired_slope); + + shade = desired_shade; + opp_shade = 1.f - desired_shade; +} + +void root(const uchar4 *in, uchar4 *out, uint32_t x, uint32_t y) { + // Convert x and y to floating point coordinates with center as origin + const float4 fin = convert_float4(*in); + const float2 inCoord = {(float)x, (float)y}; + const float2 coord = mad(inCoord, inv_dimensions, neg_center); + const float sloped_dist_ratio = fast_length(axis_scale * coord) * sloped_inv_max_dist; + // TODO: add half_exp once implemented + const float lumen = opp_shade + shade * half_recip(1.f + sloped_neg_range * exp(sloped_dist_ratio)); + float4 fout; + fout.rgb = fin.rgb * lumen; + fout.w = fin.w; + *out = convert_uchar4(fout); +} + diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette_approx_full.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette_approx_full.rs new file mode 100644 index 0000000..3612509 --- /dev/null +++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette_approx_full.rs @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2012 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. + */ + +#pragma version(1) +#pragma rs java_package_name(com.android.rs.image2) + +#include "vignette_approx.rsh" + diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette_approx_relaxed.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette_approx_relaxed.rs new file mode 100644 index 0000000..b714e9b --- /dev/null +++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette_approx_relaxed.rs @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2012 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. + */ + +#pragma version(1) +#pragma rs java_package_name(com.android.rs.image2) +#pragma rs_fp_relaxed + +#include "vignette_approx.rsh" + |