summaryrefslogtreecommitdiffstats
path: root/samples
diff options
context:
space:
mode:
authorAlexander Lucas <alexlucas@google.com>2014-02-08 18:34:50 +0000
committerAndroid Git Automerger <android-git-automerger@android.com>2014-02-08 18:34:50 +0000
commitec6c668327abf0f569824363a3b24dc6f41c340e (patch)
tree4f9d5b3fc0c3df65e088b97f76be7f03bcc52a04 /samples
parentbcb343c42c2fb7fa4fb252ac5bb333ff87b4793e (diff)
parent743e1fd6ad69e15ad519a77ddb9d7ff00011f39f (diff)
downloadandroid_development-ec6c668327abf0f569824363a3b24dc6f41c340e.tar.gz
android_development-ec6c668327abf0f569824363a3b24dc6f41c340e.tar.bz2
android_development-ec6c668327abf0f569824363a3b24dc6f41c340e.zip
am 743e1fd6: am 0b3758ea: Adding new samples to browseable section of DAC
* commit '743e1fd6ad69e15ad519a77ddb9d7ff00011f39f': Adding new samples to browseable section of DAC
Diffstat (limited to 'samples')
-rw-r--r--samples/browseable/ActivityInstrumentation/res/values-sw600dp/template-dimens.xml (renamed from samples/browseable/ActivityInstrumentation/res/values-sw600dp/dimens.xml)0
-rw-r--r--samples/browseable/ActivityInstrumentation/res/values-sw600dp/template-styles.xml (renamed from samples/browseable/ActivityInstrumentation/res/values-sw600dp/styles.xml)0
-rw-r--r--samples/browseable/ActivityInstrumentation/res/values/dimens.xml44
-rw-r--r--samples/browseable/ActivityInstrumentation/res/values/template-dimens.xml (renamed from samples/browseable/AdvancedImmersiveMode/res/values/dimens.xml)0
-rw-r--r--samples/browseable/ActivityInstrumentation/res/values/template-styles.xml (renamed from samples/browseable/ActivityInstrumentation/res/values/styles.xml)0
-rwxr-xr-xsamples/browseable/AdvancedImmersiveMode/res/layout-w720dp/activity_main.xml73
-rw-r--r--samples/browseable/AdvancedImmersiveMode/res/layout/fragment_flags.xml69
-rw-r--r--samples/browseable/AdvancedImmersiveMode/res/values-sw600dp/template-dimens.xml (renamed from samples/browseable/AdvancedImmersiveMode/res/values-sw600dp/dimens.xml)0
-rw-r--r--samples/browseable/AdvancedImmersiveMode/res/values-sw600dp/template-styles.xml (renamed from samples/browseable/AdvancedImmersiveMode/res/values-sw600dp/styles.xml)0
-rwxr-xr-x[-rw-r--r--]samples/browseable/AdvancedImmersiveMode/res/values/strings.xml0
-rw-r--r--samples/browseable/AdvancedImmersiveMode/res/values/template-dimens.xml (renamed from samples/browseable/AppRestrictions/res/values/dimens.xml)0
-rw-r--r--samples/browseable/AdvancedImmersiveMode/res/values/template-styles.xml (renamed from samples/browseable/AdvancedImmersiveMode/res/values/styles.xml)0
-rw-r--r--samples/browseable/AppRestrictions/res/values-sw600dp/template-dimens.xml (renamed from samples/browseable/AppRestrictions/res/values-sw600dp/dimens.xml)0
-rw-r--r--samples/browseable/AppRestrictions/res/values-sw600dp/template-styles.xml (renamed from samples/browseable/AppRestrictions/res/values-sw600dp/styles.xml)0
-rw-r--r--samples/browseable/AppRestrictions/res/values/template-dimens.xml (renamed from samples/browseable/BasicAndroidKeyStore/res/values/dimens.xml)0
-rw-r--r--samples/browseable/AppRestrictions/res/values/template-styles.xml (renamed from samples/browseable/AppRestrictions/res/values/styles.xml)0
-rw-r--r--samples/browseable/BasicAccessibility/res/values-sw600dp/template-dimens.xml (renamed from samples/browseable/BasicAccessibility/res/values-sw600dp/dimens.xml)0
-rw-r--r--samples/browseable/BasicAccessibility/res/values-sw600dp/template-styles.xml (renamed from samples/browseable/BasicAccessibility/res/values-sw600dp/styles.xml)0
-rw-r--r--samples/browseable/BasicAccessibility/res/values/dimens.xml40
-rw-r--r--samples/browseable/BasicAccessibility/res/values/template-dimens.xml (renamed from samples/browseable/BasicContactables/res/values/dimens.xml)0
-rw-r--r--samples/browseable/BasicAccessibility/res/values/template-styles.xml (renamed from samples/browseable/BasicAccessibility/res/values/styles.xml)0
-rw-r--r--samples/browseable/BasicAndroidKeyStore/res/layout-sw600dp-land/activity_main.xml37
-rw-r--r--samples/browseable/BasicAndroidKeyStore/res/layout-sw600dp/activity_main.xml36
-rw-r--r--samples/browseable/BasicAndroidKeyStore/res/layout/activity_main.xml3
-rw-r--r--samples/browseable/BasicAndroidKeyStore/res/values-sw600dp/template-dimens.xml (renamed from samples/browseable/BasicAndroidKeyStore/res/values-sw600dp/dimens.xml)0
-rw-r--r--samples/browseable/BasicAndroidKeyStore/res/values-sw600dp/template-styles.xml (renamed from samples/browseable/BasicAndroidKeyStore/res/values-sw600dp/styles.xml)0
-rw-r--r--samples/browseable/BasicAndroidKeyStore/res/values/template-dimens.xml (renamed from samples/browseable/BasicGestureDetect/res/values/dimens.xml)0
-rw-r--r--samples/browseable/BasicAndroidKeyStore/res/values/template-styles.xml54
-rw-r--r--samples/browseable/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/MainActivity.java3
-rw-r--r--samples/browseable/BasicContactables/res/values-sw600dp/template-dimens.xml (renamed from samples/browseable/BasicContactables/res/values-sw600dp/dimens.xml)0
-rw-r--r--samples/browseable/BasicContactables/res/values-sw600dp/template-styles.xml (renamed from samples/browseable/BasicContactables/res/values-sw600dp/styles.xml)0
-rw-r--r--samples/browseable/BasicContactables/res/values/styles.xml21
-rw-r--r--samples/browseable/BasicContactables/res/values/template-dimens.xml (renamed from samples/browseable/BasicImmersiveMode/res/values/dimens.xml)0
-rw-r--r--samples/browseable/BasicContactables/res/values/template-styles.xml (renamed from samples/browseable/BasicMediaDecoder/res/values/styles.xml)0
-rw-r--r--samples/browseable/BasicGestureDetect/res/values-sw600dp/template-dimens.xml (renamed from samples/browseable/BasicGestureDetect/res/values-sw600dp/dimens.xml)0
-rw-r--r--samples/browseable/BasicGestureDetect/res/values-sw600dp/template-styles.xml (renamed from samples/browseable/BasicGestureDetect/res/values-sw600dp/styles.xml)0
-rw-r--r--samples/browseable/BasicGestureDetect/res/values/template-dimens.xml (renamed from samples/browseable/BasicMediaDecoder/res/values/dimens.xml)0
-rw-r--r--samples/browseable/BasicGestureDetect/res/values/template-styles.xml (renamed from samples/browseable/BasicAndroidKeyStore/res/values/styles.xml)0
-rw-r--r--samples/browseable/BasicGestureDetect/src/com.example.android.basicgesturedetect/GestureListener.java4
-rw-r--r--samples/browseable/BasicImmersiveMode/res/values-sw600dp/template-dimens.xml (renamed from samples/browseable/BasicImmersiveMode/res/values-sw600dp/dimens.xml)0
-rw-r--r--samples/browseable/BasicImmersiveMode/res/values-sw600dp/template-styles.xml (renamed from samples/browseable/BasicImmersiveMode/res/values-sw600dp/styles.xml)0
-rw-r--r--samples/browseable/BasicImmersiveMode/res/values/template-dimens.xml (renamed from samples/browseable/BasicMediaRouter/res/values/dimens.xml)0
-rw-r--r--samples/browseable/BasicImmersiveMode/res/values/template-styles.xml (renamed from samples/browseable/BasicGestureDetect/res/values/styles.xml)0
-rw-r--r--samples/browseable/BasicMediaDecoder/res/values-sw600dp/template-dimens.xml (renamed from samples/browseable/BasicMediaDecoder/res/values-sw600dp/dimens.xml)0
-rw-r--r--samples/browseable/BasicMediaDecoder/res/values-sw600dp/template-styles.xml (renamed from samples/browseable/BasicMediaDecoder/res/values-sw600dp/styles.xml)0
-rw-r--r--samples/browseable/BasicMediaDecoder/res/values/template-dimens.xml (renamed from samples/browseable/BasicMultitouch/res/values/dimens.xml)0
-rw-r--r--samples/browseable/BasicMediaDecoder/res/values/template-styles.xml (renamed from samples/browseable/BasicNotifications/res/values/styles.xml)0
-rw-r--r--samples/browseable/BasicMediaRouter/res/values-sw600dp/template-dimens.xml (renamed from samples/browseable/BasicMediaRouter/res/values-sw600dp/dimens.xml)0
-rw-r--r--samples/browseable/BasicMediaRouter/res/values-sw600dp/template-styles.xml (renamed from samples/browseable/BasicMediaRouter/res/values-sw600dp/styles.xml)0
-rw-r--r--samples/browseable/BasicMediaRouter/res/values/styles.xml56
-rw-r--r--samples/browseable/BasicMediaRouter/res/values/template-dimens.xml (renamed from samples/browseable/BasicNetworking/res/values/dimens.xml)0
-rw-r--r--samples/browseable/BasicMediaRouter/res/values/template-styles.xml (renamed from samples/browseable/BasicSyncAdapter/res/values/styles.xml)0
-rw-r--r--samples/browseable/BasicMultitouch/res/values-sw600dp/template-dimens.xml (renamed from samples/browseable/BasicMultitouch/res/values-sw600dp/dimens.xml)0
-rw-r--r--samples/browseable/BasicMultitouch/res/values-sw600dp/template-styles.xml (renamed from samples/browseable/BasicMultitouch/res/values-sw600dp/styles.xml)0
-rw-r--r--samples/browseable/BasicMultitouch/res/values/styles.xml34
-rw-r--r--samples/browseable/BasicMultitouch/res/values/template-dimens.xml (renamed from samples/browseable/BasicNotifications/res/values/dimens.xml)0
-rw-r--r--samples/browseable/BasicMultitouch/res/values/template-styles.xml (renamed from samples/browseable/BluetoothLeGatt/res/values/styles.xml)0
-rw-r--r--samples/browseable/BasicNetworking/res/values-sw600dp/template-dimens.xml (renamed from samples/browseable/BasicNetworking/res/values-sw600dp/dimens.xml)0
-rw-r--r--samples/browseable/BasicNetworking/res/values-sw600dp/template-styles.xml (renamed from samples/browseable/BasicNetworking/res/values-sw600dp/styles.xml)0
-rw-r--r--samples/browseable/BasicNetworking/res/values/styles.xml22
-rw-r--r--samples/browseable/BasicNetworking/res/values/template-dimens.xml (renamed from samples/browseable/BasicSyncAdapter/res/values/dimens.xml)0
-rw-r--r--samples/browseable/BasicNetworking/res/values/template-styles.xml (renamed from samples/browseable/HorizontalPaging/res/values/styles.xml)0
-rw-r--r--samples/browseable/BasicNotifications/res/values-sw600dp/template-dimens.xml (renamed from samples/browseable/BasicNotifications/res/values-sw600dp/dimens.xml)0
-rw-r--r--samples/browseable/BasicNotifications/res/values-sw600dp/template-styles.xml (renamed from samples/browseable/BasicNotifications/res/values-sw600dp/styles.xml)0
-rw-r--r--samples/browseable/BasicNotifications/res/values/template-dimens.xml (renamed from samples/browseable/BluetoothLeGatt/res/values/dimens.xml)0
-rw-r--r--samples/browseable/BasicNotifications/res/values/template-styles.xml (renamed from samples/browseable/NetworkConnect/res/values/styles.xml)0
-rw-r--r--samples/browseable/BasicRenderScript/AndroidManifest.xml45
-rw-r--r--samples/browseable/BasicRenderScript/_index.jd13
-rwxr-xr-xsamples/browseable/BasicRenderScript/res/drawable-hdpi/ic_launcher.pngbin0 -> 4440 bytes
-rw-r--r--samples/browseable/BasicRenderScript/res/drawable-hdpi/tile.9.png (renamed from samples/browseable/repeatingAlarm/res/drawable-hdpi/tile.9.png)bin196 -> 196 bytes
-rwxr-xr-xsamples/browseable/BasicRenderScript/res/drawable-mdpi/ic_launcher.pngbin0 -> 2742 bytes
-rw-r--r--samples/browseable/BasicRenderScript/res/drawable-nodpi/data.jpgbin0 -> 76367 bytes
-rwxr-xr-xsamples/browseable/BasicRenderScript/res/drawable-xhdpi/ic_launcher.pngbin0 -> 6245 bytes
-rwxr-xr-xsamples/browseable/BasicRenderScript/res/drawable-xxhdpi/ic_launcher.pngbin0 -> 11130 bytes
-rwxr-xr-xsamples/browseable/BasicRenderScript/res/layout/activity_main.xml36
-rw-r--r--samples/browseable/BasicRenderScript/res/layout/main_layout.xml22
-rw-r--r--samples/browseable/BasicRenderScript/res/values-sw600dp/template-dimens.xml (renamed from samples/browseable/BasicSyncAdapter/res/values-sw600dp/dimens.xml)0
-rw-r--r--samples/browseable/BasicRenderScript/res/values-sw600dp/template-styles.xml (renamed from samples/browseable/BasicSyncAdapter/res/values-sw600dp/styles.xml)0
-rw-r--r--samples/browseable/BasicRenderScript/res/values-v11/styles.xml24
-rw-r--r--samples/browseable/BasicRenderScript/res/values-v14/styles.xml12
-rw-r--r--samples/browseable/BasicRenderScript/res/values/attrs.xml14
-rw-r--r--samples/browseable/BasicRenderScript/res/values/base-strings.xml32
-rw-r--r--samples/browseable/BasicRenderScript/res/values/colors.xml5
-rw-r--r--samples/browseable/BasicRenderScript/res/values/styles.xml22
-rw-r--r--samples/browseable/BasicRenderScript/res/values/template-dimens.xml (renamed from samples/browseable/DoneBar/res/values/dimens.xml)0
-rw-r--r--samples/browseable/BasicRenderScript/res/values/template-styles.xml (renamed from samples/browseable/TextSwitcher/res/values/styles.xml)0
-rw-r--r--samples/browseable/BasicRenderScript/src/com.example.android.basicrenderscript/MainActivity.java190
-rw-r--r--samples/browseable/BasicRenderScript/src/com.example.android.common.media/CameraHelper.java182
-rw-r--r--samples/browseable/BasicRenderScript/src/com.example.android.common.media/MediaCodecWrapper.java386
-rw-r--r--samples/browseable/BasicSyncAdapter/res/values-sw600dp/template-dimens.xml (renamed from samples/browseable/BluetoothLeGatt/res/values-sw600dp/dimens.xml)0
-rw-r--r--samples/browseable/BasicSyncAdapter/res/values-sw600dp/template-styles.xml (renamed from samples/browseable/BluetoothLeGatt/res/values-sw600dp/styles.xml)0
-rw-r--r--samples/browseable/BasicSyncAdapter/res/values/template-dimens.xml (renamed from samples/browseable/ImmersiveMode/res/values/dimens.xml)0
-rw-r--r--samples/browseable/BasicSyncAdapter/res/values/template-styles.xml42
-rw-r--r--samples/browseable/BatchStepSensor/AndroidManifest.xml51
-rw-r--r--samples/browseable/BatchStepSensor/_index.jd21
-rw-r--r--samples/browseable/BatchStepSensor/res/drawable-hdpi/ic_action_cancel.pngbin0 -> 438 bytes
-rw-r--r--samples/browseable/BatchStepSensor/res/drawable-hdpi/ic_launcher.pngbin0 -> 4402 bytes
-rw-r--r--samples/browseable/BatchStepSensor/res/drawable-hdpi/tile.9.pngbin0 -> 196 bytes
-rw-r--r--samples/browseable/BatchStepSensor/res/drawable-mdpi/ic_action_cancel.pngbin0 -> 328 bytes
-rw-r--r--samples/browseable/BatchStepSensor/res/drawable-mdpi/ic_launcher.pngbin0 -> 2641 bytes
-rw-r--r--samples/browseable/BatchStepSensor/res/drawable-xhdpi/card_bg.9.pngbin0 -> 442 bytes
-rw-r--r--samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_negative.pngbin0 -> 2963 bytes
-rw-r--r--samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_negative_pressed.pngbin0 -> 1671 bytes
-rw-r--r--samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_neutral.pngbin0 -> 2137 bytes
-rw-r--r--samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_neutral_pressed.pngbin0 -> 1401 bytes
-rw-r--r--samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_positive.pngbin0 -> 2201 bytes
-rw-r--r--samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_positive_pressed.pngbin0 -> 1393 bytes
-rw-r--r--samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_launcher.pngbin0 -> 6076 bytes
-rw-r--r--samples/browseable/BatchStepSensor/res/drawable-xxhdpi/ic_action_cancel.pngbin0 -> 681 bytes
-rw-r--r--samples/browseable/BatchStepSensor/res/drawable-xxhdpi/ic_launcher.pngbin0 -> 11109 bytes
-rw-r--r--samples/browseable/BatchStepSensor/res/drawable/card_action_bg.xml7
-rw-r--r--samples/browseable/BatchStepSensor/res/drawable/card_action_bg_negative.xml7
-rw-r--r--samples/browseable/BatchStepSensor/res/drawable/card_action_bg_positive.xml7
-rw-r--r--samples/browseable/BatchStepSensor/res/drawable/card_action_icon_negative.xml6
-rw-r--r--samples/browseable/BatchStepSensor/res/drawable/card_action_icon_neutral.xml6
-rw-r--r--samples/browseable/BatchStepSensor/res/drawable/card_action_icon_positive.xml6
-rw-r--r--samples/browseable/BatchStepSensor/res/drawable/card_action_text.xml7
-rw-r--r--samples/browseable/BatchStepSensor/res/drawable/card_action_text_negative.xml7
-rw-r--r--samples/browseable/BatchStepSensor/res/drawable/card_action_text_positive.xml7
-rw-r--r--samples/browseable/BatchStepSensor/res/drawable/card_overlay_focused.xml8
-rw-r--r--samples/browseable/BatchStepSensor/res/drawable/card_separator.xml7
-rwxr-xr-xsamples/browseable/BatchStepSensor/res/layout/activity_main.xml28
-rw-r--r--samples/browseable/BatchStepSensor/res/layout/card.xml74
-rw-r--r--samples/browseable/BatchStepSensor/res/layout/card_button_negative.xml25
-rw-r--r--samples/browseable/BatchStepSensor/res/layout/card_button_neutral.xml25
-rw-r--r--samples/browseable/BatchStepSensor/res/layout/card_button_positive.xml25
-rw-r--r--samples/browseable/BatchStepSensor/res/layout/card_button_seperator.xml11
-rw-r--r--samples/browseable/BatchStepSensor/res/layout/card_progress.xml23
-rw-r--r--samples/browseable/BatchStepSensor/res/layout/cardstream.xml31
-rw-r--r--samples/browseable/BatchStepSensor/res/values-sw600dp/template-dimens.xml (renamed from samples/browseable/BorderlessButtons/res/values-sw600dp/dimens.xml)0
-rw-r--r--samples/browseable/BatchStepSensor/res/values-sw600dp/template-styles.xml (renamed from samples/browseable/BorderlessButtons/res/values-sw600dp/styles.xml)0
-rw-r--r--samples/browseable/BatchStepSensor/res/values-sw720dp-land/dimens.xml5
-rw-r--r--samples/browseable/BatchStepSensor/res/values-v11/styles.xml11
-rw-r--r--samples/browseable/BatchStepSensor/res/values-v14/styles.xml12
-rw-r--r--samples/browseable/BatchStepSensor/res/values-v16/styles.xml11
-rw-r--r--samples/browseable/BatchStepSensor/res/values/attrs.xml14
-rw-r--r--samples/browseable/BatchStepSensor/res/values/base-strings.xml40
-rw-r--r--samples/browseable/BatchStepSensor/res/values/color.xml22
-rw-r--r--samples/browseable/BatchStepSensor/res/values/dimens.xml14
-rw-r--r--samples/browseable/BatchStepSensor/res/values/ids.xml9
-rw-r--r--samples/browseable/BatchStepSensor/res/values/strings.xml75
-rw-r--r--samples/browseable/BatchStepSensor/res/values/styles.xml92
-rw-r--r--samples/browseable/BatchStepSensor/res/values/template-dimens.xml (renamed from samples/browseable/NetworkConnect/res/values/dimens.xml)0
-rw-r--r--samples/browseable/BatchStepSensor/res/values/template-styles.xml42
-rw-r--r--samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/BatchStepSensorFragment.java588
-rw-r--r--samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/Card.java750
-rw-r--r--samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardActionButton.java69
-rw-r--r--samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardLayout.java94
-rw-r--r--samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStream.java25
-rw-r--r--samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStreamAnimator.java120
-rw-r--r--samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStreamFragment.java275
-rw-r--r--samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStreamLinearLayout.java569
-rw-r--r--samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStreamState.java40
-rw-r--r--samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/DefaultCardStreamAnimator.java124
-rw-r--r--samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/MainActivity.java91
-rw-r--r--samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/OnCardClickListener.java24
-rw-r--r--samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/StreamRetentionFragment.java41
-rw-r--r--samples/browseable/BatchStepSensor/src/com.example.android.common/activities/SampleActivityBase.java (renamed from samples/browseable/repeatingAlarm/src/com.example.android.common/activities/SampleActivityBase.java)0
-rw-r--r--samples/browseable/BatchStepSensor/src/com.example.android.common/logger/Log.java (renamed from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/Log.java)0
-rw-r--r--samples/browseable/BatchStepSensor/src/com.example.android.common/logger/LogFragment.java (renamed from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogFragment.java)0
-rw-r--r--samples/browseable/BatchStepSensor/src/com.example.android.common/logger/LogNode.java (renamed from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogNode.java)0
-rw-r--r--samples/browseable/BatchStepSensor/src/com.example.android.common/logger/LogView.java (renamed from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogView.java)0
-rw-r--r--samples/browseable/BatchStepSensor/src/com.example.android.common/logger/LogWrapper.java (renamed from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogWrapper.java)0
-rw-r--r--samples/browseable/BatchStepSensor/src/com.example.android.common/logger/MessageOnlyLogFilter.java (renamed from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java)0
-rw-r--r--samples/browseable/BluetoothLeGatt/res/values-sw600dp/template-dimens.xml (renamed from samples/browseable/CustomChoiceList/res/values-sw600dp/dimens.xml)0
-rw-r--r--samples/browseable/BluetoothLeGatt/res/values-sw600dp/template-styles.xml (renamed from samples/browseable/CustomChoiceList/res/values-sw600dp/styles.xml)0
-rw-r--r--samples/browseable/BluetoothLeGatt/res/values/template-dimens.xml (renamed from samples/browseable/StorageClient/res/values/dimens.xml)0
-rw-r--r--samples/browseable/BluetoothLeGatt/res/values/template-styles.xml42
-rw-r--r--samples/browseable/BorderlessButtons/res/values-sw600dp/template-dimens.xml (renamed from samples/browseable/CustomNotifications/res/values-sw600dp/dimens.xml)0
-rw-r--r--samples/browseable/BorderlessButtons/res/values-sw600dp/template-styles.xml (renamed from samples/browseable/CustomNotifications/res/values-sw600dp/styles.xml)0
-rw-r--r--samples/browseable/BorderlessButtons/res/values/dimens.xml13
-rw-r--r--samples/browseable/BorderlessButtons/res/values/styles.xml23
-rw-r--r--samples/browseable/BorderlessButtons/res/values/template-dimens.xml (renamed from samples/browseable/repeatingAlarm/res/values/dimens.xml)0
-rw-r--r--samples/browseable/BorderlessButtons/res/values/template-styles.xml42
-rw-r--r--samples/browseable/CardEmulation/AndroidManifest.xml61
-rw-r--r--samples/browseable/CardEmulation/_index.jd17
-rw-r--r--samples/browseable/CardEmulation/res/drawable-hdpi/ic_launcher.pngbin0 -> 4720 bytes
-rw-r--r--samples/browseable/CardEmulation/res/drawable-hdpi/tile.9.pngbin0 -> 196 bytes
-rw-r--r--samples/browseable/CardEmulation/res/drawable-mdpi/ic_launcher.pngbin0 -> 2805 bytes
-rw-r--r--samples/browseable/CardEmulation/res/drawable-xhdpi/ic_launcher.pngbin0 -> 6850 bytes
-rw-r--r--samples/browseable/CardEmulation/res/drawable-xxhdpi/card_background.pngbin0 -> 504418 bytes
-rw-r--r--samples/browseable/CardEmulation/res/drawable-xxhdpi/ic_launcher.pngbin0 -> 12603 bytes
-rwxr-xr-xsamples/browseable/CardEmulation/res/layout-w720dp/activity_main.xml73
-rwxr-xr-xsamples/browseable/CardEmulation/res/layout/activity_main.xml65
-rw-r--r--samples/browseable/CardEmulation/res/layout/main_fragment.xml65
-rw-r--r--samples/browseable/CardEmulation/res/menu/main.xml21
-rw-r--r--samples/browseable/CardEmulation/res/values-sw600dp/template-dimens.xml (renamed from samples/browseable/DoneBar/res/values-sw600dp/dimens.xml)0
-rw-r--r--samples/browseable/CardEmulation/res/values-sw600dp/template-styles.xml (renamed from samples/browseable/DoneBar/res/values-sw600dp/styles.xml)0
-rw-r--r--samples/browseable/CardEmulation/res/values/base-strings.xml36
-rwxr-xr-xsamples/browseable/CardEmulation/res/values/strings.xml19
-rw-r--r--samples/browseable/CardEmulation/res/values/template-dimens.xml32
-rw-r--r--samples/browseable/CardEmulation/res/values/template-styles.xml42
-rw-r--r--samples/browseable/CardEmulation/res/xml/aid_list.xml64
-rw-r--r--samples/browseable/CardEmulation/src/com.example.android.cardemulation/AccountStorage.java58
-rw-r--r--samples/browseable/CardEmulation/src/com.example.android.cardemulation/CardEmulationFragment.java70
-rw-r--r--samples/browseable/CardEmulation/src/com.example.android.cardemulation/CardService.java173
-rw-r--r--samples/browseable/CardEmulation/src/com.example.android.cardemulation/MainActivity.java110
-rw-r--r--samples/browseable/CardEmulation/src/com.example.android.common/activities/SampleActivityBase.java52
-rw-r--r--samples/browseable/CardEmulation/src/com.example.android.common/logger/Log.java236
-rw-r--r--samples/browseable/CardEmulation/src/com.example.android.common/logger/LogFragment.java109
-rw-r--r--samples/browseable/CardEmulation/src/com.example.android.common/logger/LogNode.java39
-rw-r--r--samples/browseable/CardEmulation/src/com.example.android.common/logger/LogView.java145
-rw-r--r--samples/browseable/CardEmulation/src/com.example.android.common/logger/LogWrapper.java75
-rw-r--r--samples/browseable/CardEmulation/src/com.example.android.common/logger/MessageOnlyLogFilter.java60
-rw-r--r--samples/browseable/CardReader/AndroidManifest.xml53
-rw-r--r--samples/browseable/CardReader/_index.jd17
-rw-r--r--samples/browseable/CardReader/res/drawable-hdpi/ic_launcher.pngbin0 -> 3973 bytes
-rw-r--r--samples/browseable/CardReader/res/drawable-hdpi/tile.9.pngbin0 -> 196 bytes
-rw-r--r--samples/browseable/CardReader/res/drawable-mdpi/ic_launcher.pngbin0 -> 2405 bytes
-rw-r--r--samples/browseable/CardReader/res/drawable-xhdpi/ic_launcher.pngbin0 -> 5544 bytes
-rw-r--r--samples/browseable/CardReader/res/drawable-xxhdpi/card_background.pngbin0 -> 504418 bytes
-rw-r--r--samples/browseable/CardReader/res/drawable-xxhdpi/ic_launcher.pngbin0 -> 10192 bytes
-rwxr-xr-xsamples/browseable/CardReader/res/layout-w720dp/activity_main.xml73
-rwxr-xr-xsamples/browseable/CardReader/res/layout/activity_main.xml65
-rw-r--r--samples/browseable/CardReader/res/layout/main_fragment.xml64
-rw-r--r--samples/browseable/CardReader/res/menu/main.xml21
-rw-r--r--samples/browseable/CardReader/res/values-sw600dp/template-dimens.xml (renamed from samples/browseable/HorizontalPaging/res/values-sw600dp/dimens.xml)0
-rw-r--r--samples/browseable/CardReader/res/values-sw600dp/template-styles.xml (renamed from samples/browseable/HorizontalPaging/res/values-sw600dp/styles.xml)0
-rw-r--r--samples/browseable/CardReader/res/values/base-strings.xml36
-rwxr-xr-xsamples/browseable/CardReader/res/values/strings.xml19
-rw-r--r--samples/browseable/CardReader/res/values/template-dimens.xml32
-rw-r--r--samples/browseable/CardReader/res/values/template-styles.xml42
-rw-r--r--samples/browseable/CardReader/res/xml/nfc_tech_filter.xml8
-rw-r--r--samples/browseable/CardReader/src/com.example.android.cardreader/CardReaderFragment.java109
-rw-r--r--samples/browseable/CardReader/src/com.example.android.cardreader/LoyaltyCardReader.java149
-rw-r--r--samples/browseable/CardReader/src/com.example.android.cardreader/MainActivity.java110
-rw-r--r--samples/browseable/CardReader/src/com.example.android.common/activities/SampleActivityBase.java52
-rw-r--r--samples/browseable/CardReader/src/com.example.android.common/logger/Log.java236
-rw-r--r--samples/browseable/CardReader/src/com.example.android.common/logger/LogFragment.java109
-rw-r--r--samples/browseable/CardReader/src/com.example.android.common/logger/LogNode.java39
-rw-r--r--samples/browseable/CardReader/src/com.example.android.common/logger/LogView.java145
-rw-r--r--samples/browseable/CardReader/src/com.example.android.common/logger/LogWrapper.java75
-rw-r--r--samples/browseable/CardReader/src/com.example.android.common/logger/MessageOnlyLogFilter.java60
-rw-r--r--samples/browseable/CustomChoiceList/res/values-sw600dp/template-dimens.xml (renamed from samples/browseable/ImmersiveMode/res/values-sw600dp/dimens.xml)0
-rw-r--r--samples/browseable/CustomChoiceList/res/values-sw600dp/template-styles.xml (renamed from samples/browseable/ImmersiveMode/res/values-sw600dp/styles.xml)0
-rw-r--r--samples/browseable/CustomChoiceList/res/values/dimens.xml13
-rw-r--r--samples/browseable/CustomChoiceList/res/values/styles.xml26
-rw-r--r--samples/browseable/CustomChoiceList/res/values/template-dimens.xml32
-rw-r--r--samples/browseable/CustomChoiceList/res/values/template-styles.xml42
-rw-r--r--samples/browseable/CustomNotifications/res/values-sw600dp/template-dimens.xml (renamed from samples/browseable/NetworkConnect/res/values-sw600dp/dimens.xml)0
-rw-r--r--samples/browseable/CustomNotifications/res/values-sw600dp/template-styles.xml (renamed from samples/browseable/NetworkConnect/res/values-sw600dp/styles.xml)0
-rw-r--r--samples/browseable/CustomNotifications/res/values/dimens.xml42
-rw-r--r--samples/browseable/CustomNotifications/res/values/styles.xml48
-rw-r--r--samples/browseable/CustomNotifications/res/values/template-dimens.xml32
-rw-r--r--samples/browseable/CustomNotifications/res/values/template-styles.xml42
-rw-r--r--samples/browseable/DoneBar/res/values-sw600dp/template-dimens.xml (renamed from samples/browseable/StorageClient/res/values-sw600dp/dimens.xml)0
-rw-r--r--samples/browseable/DoneBar/res/values-sw600dp/template-styles.xml (renamed from samples/browseable/StorageClient/res/values-sw600dp/styles.xml)0
-rw-r--r--samples/browseable/DoneBar/res/values/template-dimens.xml32
-rw-r--r--samples/browseable/DoneBar/res/values/template-styles.xml (renamed from samples/browseable/DoneBar/res/values/styles.xml)0
-rw-r--r--samples/browseable/HorizontalPaging/res/values-sw600dp/template-dimens.xml (renamed from samples/browseable/TextLinkify/res/values-sw600dp/dimens.xml)0
-rw-r--r--samples/browseable/HorizontalPaging/res/values-sw600dp/template-styles.xml (renamed from samples/browseable/TextLinkify/res/values-sw600dp/styles.xml)0
-rw-r--r--samples/browseable/HorizontalPaging/res/values/dimens.xml33
-rw-r--r--samples/browseable/HorizontalPaging/res/values/template-dimens.xml32
-rw-r--r--samples/browseable/HorizontalPaging/res/values/template-styles.xml42
-rw-r--r--samples/browseable/ImmersiveMode/res/values-sw600dp/template-dimens.xml (renamed from samples/browseable/repeatingAlarm/res/values-sw600dp/dimens.xml)0
-rw-r--r--samples/browseable/ImmersiveMode/res/values-sw600dp/template-styles.xml (renamed from samples/browseable/TextSwitcher/res/values-sw600dp/styles.xml)0
-rw-r--r--samples/browseable/ImmersiveMode/res/values/template-dimens.xml32
-rw-r--r--samples/browseable/ImmersiveMode/res/values/template-styles.xml (renamed from samples/browseable/BasicImmersiveMode/res/values/styles.xml)0
-rw-r--r--samples/browseable/MediaRecorder/res/drawable-hdpi/tile.9.pngbin0 -> 196 bytes
-rwxr-xr-xsamples/browseable/MediaRecorder/res/layout/activity_main.xml36
-rw-r--r--samples/browseable/MediaRecorder/res/values-sw600dp/template-dimens.xml24
-rw-r--r--samples/browseable/MediaRecorder/res/values-sw600dp/template-styles.xml (renamed from samples/browseable/repeatingAlarm/res/values-sw600dp/styles.xml)0
-rw-r--r--samples/browseable/MediaRecorder/res/values/base-strings.xml33
-rw-r--r--samples/browseable/MediaRecorder/res/values/template-dimens.xml32
-rw-r--r--samples/browseable/MediaRecorder/res/values/template-styles.xml42
-rw-r--r--samples/browseable/MediaRecorder/src/com.example.android.common.media/CameraHelper.java182
-rw-r--r--samples/browseable/MediaRecorder/src/com.example.android.common.media/MediaCodecWrapper.java386
-rw-r--r--samples/browseable/NetworkConnect/res/values-sw600dp/template-dimens.xml24
-rw-r--r--samples/browseable/NetworkConnect/res/values-sw600dp/template-styles.xml25
-rw-r--r--samples/browseable/NetworkConnect/res/values/template-dimens.xml32
-rw-r--r--samples/browseable/NetworkConnect/res/values/template-styles.xml42
-rw-r--r--samples/browseable/RenderScriptIntrinsic/AndroidManifest.xml45
-rw-r--r--samples/browseable/RenderScriptIntrinsic/_index.jd14
-rwxr-xr-xsamples/browseable/RenderScriptIntrinsic/res/drawable-hdpi/ic_launcher.pngbin0 -> 4440 bytes
-rw-r--r--samples/browseable/RenderScriptIntrinsic/res/drawable-hdpi/tile.9.pngbin0 -> 196 bytes
-rwxr-xr-xsamples/browseable/RenderScriptIntrinsic/res/drawable-mdpi/ic_launcher.pngbin0 -> 2742 bytes
-rw-r--r--samples/browseable/RenderScriptIntrinsic/res/drawable-nodpi/data.jpgbin0 -> 777765 bytes
-rwxr-xr-xsamples/browseable/RenderScriptIntrinsic/res/drawable-xhdpi/ic_launcher.pngbin0 -> 6245 bytes
-rwxr-xr-xsamples/browseable/RenderScriptIntrinsic/res/drawable-xxhdpi/ic_launcher.pngbin0 -> 11130 bytes
-rwxr-xr-xsamples/browseable/RenderScriptIntrinsic/res/layout/activity_main.xml36
-rw-r--r--samples/browseable/RenderScriptIntrinsic/res/layout/main_layout.xml51
-rw-r--r--samples/browseable/RenderScriptIntrinsic/res/values-sw600dp/template-dimens.xml24
-rw-r--r--samples/browseable/RenderScriptIntrinsic/res/values-sw600dp/template-styles.xml25
-rw-r--r--samples/browseable/RenderScriptIntrinsic/res/values-v11/styles.xml24
-rw-r--r--samples/browseable/RenderScriptIntrinsic/res/values-v14/styles.xml12
-rw-r--r--samples/browseable/RenderScriptIntrinsic/res/values/attrs.xml14
-rw-r--r--samples/browseable/RenderScriptIntrinsic/res/values/base-strings.xml33
-rw-r--r--samples/browseable/RenderScriptIntrinsic/res/values/colors.xml5
-rw-r--r--samples/browseable/RenderScriptIntrinsic/res/values/styles.xml33
-rw-r--r--samples/browseable/RenderScriptIntrinsic/res/values/template-dimens.xml32
-rw-r--r--samples/browseable/RenderScriptIntrinsic/res/values/template-styles.xml42
-rw-r--r--samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/Log.java236
-rw-r--r--samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/LogFragment.java109
-rw-r--r--samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/LogNode.java39
-rw-r--r--samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/LogView.java145
-rw-r--r--samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/LogWrapper.java75
-rw-r--r--samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/MessageOnlyLogFilter.java60
-rw-r--r--samples/browseable/RenderScriptIntrinsic/src/com.example.android.renderscriptintrinsic/MainActivity.java370
-rw-r--r--samples/browseable/RenderScriptIntrinsic/src/com.example.android.renderscriptintrinsic/ThumbnailRadioButton.java111
-rw-r--r--samples/browseable/RepeatingAlarm/AndroidManifest.xml (renamed from samples/browseable/repeatingAlarm/AndroidManifest.xml)0
-rw-r--r--samples/browseable/RepeatingAlarm/_index.jd13
-rw-r--r--samples/browseable/RepeatingAlarm/res/drawable-hdpi/ic_launcher.png (renamed from samples/browseable/repeatingAlarm/res/drawable-hdpi/ic_launcher.png)bin4199 -> 4199 bytes
-rw-r--r--samples/browseable/RepeatingAlarm/res/drawable-hdpi/tile.9.pngbin0 -> 196 bytes
-rw-r--r--samples/browseable/RepeatingAlarm/res/drawable-mdpi/ic_launcher.png (renamed from samples/browseable/repeatingAlarm/res/drawable-mdpi/ic_launcher.png)bin2535 -> 2535 bytes
-rw-r--r--samples/browseable/RepeatingAlarm/res/drawable-xhdpi/ic_launcher.png (renamed from samples/browseable/repeatingAlarm/res/drawable-xhdpi/ic_launcher.png)bin6022 -> 6022 bytes
-rw-r--r--samples/browseable/RepeatingAlarm/res/drawable-xxhdpi/ic_launcher.png (renamed from samples/browseable/repeatingAlarm/res/drawable-xxhdpi/ic_launcher.png)bin11040 -> 11040 bytes
-rwxr-xr-xsamples/browseable/RepeatingAlarm/res/layout/activity_main.xml (renamed from samples/browseable/repeatingAlarm/res/layout/activity_main.xml)0
-rw-r--r--samples/browseable/RepeatingAlarm/res/menu/main.xml (renamed from samples/browseable/repeatingAlarm/res/menu/main.xml)0
-rw-r--r--samples/browseable/RepeatingAlarm/res/values-sw600dp/template-dimens.xml24
-rw-r--r--samples/browseable/RepeatingAlarm/res/values-sw600dp/template-styles.xml25
-rw-r--r--samples/browseable/RepeatingAlarm/res/values/base-strings.xml (renamed from samples/browseable/repeatingAlarm/res/values/base-strings.xml)2
-rw-r--r--samples/browseable/RepeatingAlarm/res/values/strings.xml (renamed from samples/browseable/repeatingAlarm/res/values/strings.xml)0
-rw-r--r--samples/browseable/RepeatingAlarm/res/values/template-dimens.xml32
-rw-r--r--samples/browseable/RepeatingAlarm/res/values/template-styles.xml (renamed from samples/browseable/ImmersiveMode/res/values/styles.xml)0
-rw-r--r--samples/browseable/RepeatingAlarm/src/com.example.android.common/activities/SampleActivityBase.java52
-rw-r--r--samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/Log.java236
-rw-r--r--samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/LogFragment.java109
-rw-r--r--samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/LogNode.java39
-rw-r--r--samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/LogView.java145
-rw-r--r--samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/LogWrapper.java75
-rw-r--r--samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java60
-rw-r--r--samples/browseable/RepeatingAlarm/src/com.example.android.repeatingalarm/MainActivity.java (renamed from samples/browseable/repeatingAlarm/src/com.example.android.repeatingalarm/MainActivity.java)0
-rw-r--r--samples/browseable/RepeatingAlarm/src/com.example.android.repeatingalarm/RepeatingAlarmFragment.java (renamed from samples/browseable/repeatingAlarm/src/com.example.android.repeatingalarm/RepeatingAlarmFragment.java)0
-rw-r--r--samples/browseable/SlidingTabsBasic/AndroidManifest.xml42
-rw-r--r--samples/browseable/SlidingTabsBasic/_index.jd13
-rw-r--r--samples/browseable/SlidingTabsBasic/res/drawable-hdpi/ic_launcher.pngbin0 -> 3618 bytes
-rw-r--r--samples/browseable/SlidingTabsBasic/res/drawable-hdpi/tile.9.pngbin0 -> 196 bytes
-rw-r--r--samples/browseable/SlidingTabsBasic/res/drawable-mdpi/ic_launcher.pngbin0 -> 2262 bytes
-rw-r--r--samples/browseable/SlidingTabsBasic/res/drawable-xhdpi/ic_launcher.pngbin0 -> 5011 bytes
-rw-r--r--samples/browseable/SlidingTabsBasic/res/drawable-xxhdpi/ic_launcher.pngbin0 -> 9174 bytes
-rwxr-xr-xsamples/browseable/SlidingTabsBasic/res/layout-w720dp/activity_main.xml73
-rwxr-xr-xsamples/browseable/SlidingTabsBasic/res/layout/activity_main.xml65
-rw-r--r--samples/browseable/SlidingTabsBasic/res/layout/fragment_sample.xml19
-rw-r--r--samples/browseable/SlidingTabsBasic/res/layout/pager_item.xml22
-rw-r--r--samples/browseable/SlidingTabsBasic/res/menu/main.xml21
-rw-r--r--samples/browseable/SlidingTabsBasic/res/values-sw600dp/template-dimens.xml24
-rw-r--r--samples/browseable/SlidingTabsBasic/res/values-sw600dp/template-styles.xml25
-rw-r--r--samples/browseable/SlidingTabsBasic/res/values/base-strings.xml32
-rwxr-xr-xsamples/browseable/SlidingTabsBasic/res/values/strings.xml19
-rw-r--r--samples/browseable/SlidingTabsBasic/res/values/template-dimens.xml32
-rw-r--r--samples/browseable/SlidingTabsBasic/res/values/template-styles.xml42
-rw-r--r--samples/browseable/SlidingTabsBasic/src/com.example.android.common/activities/SampleActivityBase.java52
-rw-r--r--samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/Log.java236
-rw-r--r--samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/LogFragment.java109
-rw-r--r--samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/LogNode.java39
-rw-r--r--samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/LogView.java145
-rw-r--r--samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/LogWrapper.java75
-rw-r--r--samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/MessageOnlyLogFilter.java60
-rw-r--r--samples/browseable/SlidingTabsBasic/src/com.example.android.common/view/SlidingTabLayout.java314
-rw-r--r--samples/browseable/SlidingTabsBasic/src/com.example.android.common/view/SlidingTabStrip.java208
-rw-r--r--samples/browseable/SlidingTabsBasic/src/com.example.android.slidingtabsbasic/MainActivity.java110
-rw-r--r--samples/browseable/SlidingTabsBasic/src/com.example.android.slidingtabsbasic/SlidingTabsBasicFragment.java160
-rw-r--r--samples/browseable/SlidingTabsColors/AndroidManifest.xml42
-rw-r--r--samples/browseable/SlidingTabsColors/_index.jd13
-rw-r--r--samples/browseable/SlidingTabsColors/res/drawable-hdpi/ic_launcher.pngbin0 -> 3852 bytes
-rw-r--r--samples/browseable/SlidingTabsColors/res/drawable-hdpi/tile.9.pngbin0 -> 196 bytes
-rw-r--r--samples/browseable/SlidingTabsColors/res/drawable-mdpi/ic_launcher.pngbin0 -> 2401 bytes
-rw-r--r--samples/browseable/SlidingTabsColors/res/drawable-xhdpi/ic_launcher.pngbin0 -> 5410 bytes
-rw-r--r--samples/browseable/SlidingTabsColors/res/drawable-xxhdpi/ic_launcher.pngbin0 -> 9697 bytes
-rwxr-xr-xsamples/browseable/SlidingTabsColors/res/layout-w720dp/activity_main.xml73
-rwxr-xr-xsamples/browseable/SlidingTabsColors/res/layout/activity_main.xml65
-rw-r--r--samples/browseable/SlidingTabsColors/res/layout/fragment_sample.xml19
-rw-r--r--samples/browseable/SlidingTabsColors/res/layout/pager_item.xml27
-rw-r--r--samples/browseable/SlidingTabsColors/res/menu/main.xml21
-rw-r--r--samples/browseable/SlidingTabsColors/res/values-sw600dp/template-dimens.xml24
-rw-r--r--samples/browseable/SlidingTabsColors/res/values-sw600dp/template-styles.xml25
-rw-r--r--samples/browseable/SlidingTabsColors/res/values/base-strings.xml32
-rwxr-xr-xsamples/browseable/SlidingTabsColors/res/values/strings.xml19
-rw-r--r--samples/browseable/SlidingTabsColors/res/values/template-dimens.xml32
-rw-r--r--samples/browseable/SlidingTabsColors/res/values/template-styles.xml42
-rw-r--r--samples/browseable/SlidingTabsColors/src/com.example.android.common/activities/SampleActivityBase.java52
-rw-r--r--samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/Log.java236
-rw-r--r--samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/LogFragment.java109
-rw-r--r--samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/LogNode.java39
-rw-r--r--samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/LogView.java145
-rw-r--r--samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/LogWrapper.java75
-rw-r--r--samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/MessageOnlyLogFilter.java60
-rw-r--r--samples/browseable/SlidingTabsColors/src/com.example.android.common/view/SlidingTabLayout.java314
-rw-r--r--samples/browseable/SlidingTabsColors/src/com.example.android.common/view/SlidingTabStrip.java208
-rw-r--r--samples/browseable/SlidingTabsColors/src/com.example.android.slidingtabscolors/ContentFragment.java80
-rw-r--r--samples/browseable/SlidingTabsColors/src/com.example.android.slidingtabscolors/MainActivity.java110
-rw-r--r--samples/browseable/SlidingTabsColors/src/com.example.android.slidingtabscolors/SlidingTabsColorsFragment.java239
-rw-r--r--samples/browseable/StorageClient/res/values-sw600dp/template-dimens.xml24
-rw-r--r--samples/browseable/StorageClient/res/values-sw600dp/template-styles.xml25
-rw-r--r--samples/browseable/StorageClient/res/values/template-dimens.xml32
-rw-r--r--samples/browseable/StorageClient/res/values/template-styles.xml (renamed from samples/browseable/StorageClient/res/values/styles.xml)0
-rw-r--r--samples/browseable/TextLinkify/res/values-sw600dp/template-dimens.xml24
-rw-r--r--samples/browseable/TextLinkify/res/values-sw600dp/template-styles.xml25
-rw-r--r--samples/browseable/TextLinkify/res/values/dimens.xml19
-rw-r--r--samples/browseable/TextLinkify/res/values/styles.xml32
-rw-r--r--samples/browseable/TextLinkify/res/values/template-dimens.xml32
-rw-r--r--samples/browseable/TextLinkify/res/values/template-styles.xml42
-rw-r--r--samples/browseable/TextSwitcher/res/values-sw600dp/dimens.xml12
-rw-r--r--samples/browseable/TextSwitcher/res/values-sw600dp/template-dimens.xml24
-rw-r--r--samples/browseable/TextSwitcher/res/values-sw600dp/template-styles.xml25
-rw-r--r--samples/browseable/TextSwitcher/res/values/dimens.xml19
-rw-r--r--samples/browseable/TextSwitcher/res/values/template-dimens.xml32
-rw-r--r--samples/browseable/TextSwitcher/res/values/template-styles.xml42
-rw-r--r--samples/browseable/repeatingAlarm/_index.jd9
-rw-r--r--samples/browseable/repeatingAlarm/res/values/styles.xml51
400 files changed, 16062 insertions, 421 deletions
diff --git a/samples/browseable/ActivityInstrumentation/res/values-sw600dp/dimens.xml b/samples/browseable/ActivityInstrumentation/res/values-sw600dp/template-dimens.xml
index 22074a2bd..22074a2bd 100644
--- a/samples/browseable/ActivityInstrumentation/res/values-sw600dp/dimens.xml
+++ b/samples/browseable/ActivityInstrumentation/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/ActivityInstrumentation/res/values-sw600dp/styles.xml b/samples/browseable/ActivityInstrumentation/res/values-sw600dp/template-styles.xml
index 03d197418..03d197418 100644
--- a/samples/browseable/ActivityInstrumentation/res/values-sw600dp/styles.xml
+++ b/samples/browseable/ActivityInstrumentation/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/ActivityInstrumentation/res/values/dimens.xml b/samples/browseable/ActivityInstrumentation/res/values/dimens.xml
index 39e710b5c..4afc9dd15 100644
--- a/samples/browseable/ActivityInstrumentation/res/values/dimens.xml
+++ b/samples/browseable/ActivityInstrumentation/res/values/dimens.xml
@@ -1,32 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright 2013 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.
+ ~ Copyright 2013 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
-->
<resources>
-
- <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
-
- <dimen name="margin_tiny">4dp</dimen>
- <dimen name="margin_small">8dp</dimen>
- <dimen name="margin_medium">16dp</dimen>
- <dimen name="margin_large">32dp</dimen>
- <dimen name="margin_huge">64dp</dimen>
-
- <!-- Semantic definitions -->
-
- <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
- <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
-
+ <!-- Default screen margins, per the Android Design guidelines. -->
+ <dimen name="activity_horizontal_margin">16dp</dimen>
+ <dimen name="activity_vertical_margin">16dp</dimen>
</resources>
diff --git a/samples/browseable/AdvancedImmersiveMode/res/values/dimens.xml b/samples/browseable/ActivityInstrumentation/res/values/template-dimens.xml
index 39e710b5c..39e710b5c 100644
--- a/samples/browseable/AdvancedImmersiveMode/res/values/dimens.xml
+++ b/samples/browseable/ActivityInstrumentation/res/values/template-dimens.xml
diff --git a/samples/browseable/ActivityInstrumentation/res/values/styles.xml b/samples/browseable/ActivityInstrumentation/res/values/template-styles.xml
index 404623e3d..404623e3d 100644
--- a/samples/browseable/ActivityInstrumentation/res/values/styles.xml
+++ b/samples/browseable/ActivityInstrumentation/res/values/template-styles.xml
diff --git a/samples/browseable/AdvancedImmersiveMode/res/layout-w720dp/activity_main.xml b/samples/browseable/AdvancedImmersiveMode/res/layout-w720dp/activity_main.xml
new file mode 100755
index 000000000..c9a52f621
--- /dev/null
+++ b/samples/browseable/AdvancedImmersiveMode/res/layout-w720dp/activity_main.xml
@@ -0,0 +1,73 @@
+<!--
+ Copyright 2013 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.
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/sample_main_layout">
+
+ <LinearLayout
+ android:id="@+id/sample_output"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:orientation="vertical">
+
+ <FrameLayout
+ style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/margin_medium"
+ android:paddingRight="@dimen/margin_medium"
+ android:paddingTop="@dimen/margin_large"
+ android:paddingBottom="@dimen/margin_large"
+ android:text="@string/intro_message" />
+ </FrameLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@android:color/darker_gray" />
+
+ <fragment
+ android:name="com.example.android.common.logger.LogFragment"
+ android:id="@+id/log_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1" />
+
+ </LinearLayout>
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:background="@android:color/darker_gray" />
+
+ <FrameLayout
+ android:id="@+id/sample_content_fragment"
+ android:layout_weight="2"
+ android:layout_width="0px"
+ android:layout_height="match_parent" />
+
+</LinearLayout>
+
+
diff --git a/samples/browseable/AdvancedImmersiveMode/res/layout/fragment_flags.xml b/samples/browseable/AdvancedImmersiveMode/res/layout/fragment_flags.xml
new file mode 100644
index 000000000..2c74e83f0
--- /dev/null
+++ b/samples/browseable/AdvancedImmersiveMode/res/layout/fragment_flags.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical" android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <CheckBox
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/flag_enable_lowprof"
+ android:text="Enable Low Profile Mode" />
+
+ <CheckBox
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/flag_hide_navbar"
+ android:text="Hide Navigation bar" />
+
+ <CheckBox
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/flag_hide_statbar"
+ android:text="Hide Status Bar" />
+
+ <CheckBox
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/flag_enable_immersive"
+ android:text="Enable Immersive Mode" />
+
+ <CheckBox
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/flag_enable_immersive_sticky"
+ android:text="Enable Immersive Mode (Sticky)" />
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Do things!"
+ android:id="@+id/btn_changeFlags" />
+
+
+ <TextView
+ android:layout_marginTop="@dimen/margin_large"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Common flag presets"/>
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal" android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Immersive Mode"
+ android:id="@+id/btn_immersive" />
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Leanback Mode"
+ android:id="@+id/btn_leanback" />
+
+ </LinearLayout>
+
+
+
+</LinearLayout> \ No newline at end of file
diff --git a/samples/browseable/AdvancedImmersiveMode/res/values-sw600dp/dimens.xml b/samples/browseable/AdvancedImmersiveMode/res/values-sw600dp/template-dimens.xml
index 22074a2bd..22074a2bd 100644
--- a/samples/browseable/AdvancedImmersiveMode/res/values-sw600dp/dimens.xml
+++ b/samples/browseable/AdvancedImmersiveMode/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/AdvancedImmersiveMode/res/values-sw600dp/styles.xml b/samples/browseable/AdvancedImmersiveMode/res/values-sw600dp/template-styles.xml
index 03d197418..03d197418 100644
--- a/samples/browseable/AdvancedImmersiveMode/res/values-sw600dp/styles.xml
+++ b/samples/browseable/AdvancedImmersiveMode/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/AdvancedImmersiveMode/res/values/strings.xml b/samples/browseable/AdvancedImmersiveMode/res/values/strings.xml
index a65b8916a..a65b8916a 100644..100755
--- a/samples/browseable/AdvancedImmersiveMode/res/values/strings.xml
+++ b/samples/browseable/AdvancedImmersiveMode/res/values/strings.xml
diff --git a/samples/browseable/AppRestrictions/res/values/dimens.xml b/samples/browseable/AdvancedImmersiveMode/res/values/template-dimens.xml
index 39e710b5c..39e710b5c 100644
--- a/samples/browseable/AppRestrictions/res/values/dimens.xml
+++ b/samples/browseable/AdvancedImmersiveMode/res/values/template-dimens.xml
diff --git a/samples/browseable/AdvancedImmersiveMode/res/values/styles.xml b/samples/browseable/AdvancedImmersiveMode/res/values/template-styles.xml
index d3f82ff64..d3f82ff64 100644
--- a/samples/browseable/AdvancedImmersiveMode/res/values/styles.xml
+++ b/samples/browseable/AdvancedImmersiveMode/res/values/template-styles.xml
diff --git a/samples/browseable/AppRestrictions/res/values-sw600dp/dimens.xml b/samples/browseable/AppRestrictions/res/values-sw600dp/template-dimens.xml
index 22074a2bd..22074a2bd 100644
--- a/samples/browseable/AppRestrictions/res/values-sw600dp/dimens.xml
+++ b/samples/browseable/AppRestrictions/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/AppRestrictions/res/values-sw600dp/styles.xml b/samples/browseable/AppRestrictions/res/values-sw600dp/template-styles.xml
index 03d197418..03d197418 100644
--- a/samples/browseable/AppRestrictions/res/values-sw600dp/styles.xml
+++ b/samples/browseable/AppRestrictions/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/BasicAndroidKeyStore/res/values/dimens.xml b/samples/browseable/AppRestrictions/res/values/template-dimens.xml
index 39e710b5c..39e710b5c 100644
--- a/samples/browseable/BasicAndroidKeyStore/res/values/dimens.xml
+++ b/samples/browseable/AppRestrictions/res/values/template-dimens.xml
diff --git a/samples/browseable/AppRestrictions/res/values/styles.xml b/samples/browseable/AppRestrictions/res/values/template-styles.xml
index 404623e3d..404623e3d 100644
--- a/samples/browseable/AppRestrictions/res/values/styles.xml
+++ b/samples/browseable/AppRestrictions/res/values/template-styles.xml
diff --git a/samples/browseable/BasicAccessibility/res/values-sw600dp/dimens.xml b/samples/browseable/BasicAccessibility/res/values-sw600dp/template-dimens.xml
index 22074a2bd..22074a2bd 100644
--- a/samples/browseable/BasicAccessibility/res/values-sw600dp/dimens.xml
+++ b/samples/browseable/BasicAccessibility/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/BasicAccessibility/res/values-sw600dp/styles.xml b/samples/browseable/BasicAccessibility/res/values-sw600dp/template-styles.xml
index 03d197418..03d197418 100644
--- a/samples/browseable/BasicAccessibility/res/values-sw600dp/styles.xml
+++ b/samples/browseable/BasicAccessibility/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/BasicAccessibility/res/values/dimens.xml b/samples/browseable/BasicAccessibility/res/values/dimens.xml
index 39e710b5c..a5e4ebef3 100644
--- a/samples/browseable/BasicAccessibility/res/values/dimens.xml
+++ b/samples/browseable/BasicAccessibility/res/values/dimens.xml
@@ -1,32 +1,20 @@
<!--
- Copyright 2013 The Android Open Source Project
+Copyright (C) 2013 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
+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.
- -->
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
<resources>
-
- <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
-
- <dimen name="margin_tiny">4dp</dimen>
- <dimen name="margin_small">8dp</dimen>
- <dimen name="margin_medium">16dp</dimen>
- <dimen name="margin_large">32dp</dimen>
- <dimen name="margin_huge">64dp</dimen>
-
- <!-- Semantic definitions -->
-
- <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
- <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
-
+ <!-- Default screen margins, per the Android Design guidelines. -->
+ <dimen name="activity_horizontal_margin">16dp</dimen>
+ <dimen name="activity_vertical_margin">16dp</dimen>
</resources>
diff --git a/samples/browseable/BasicContactables/res/values/dimens.xml b/samples/browseable/BasicAccessibility/res/values/template-dimens.xml
index 39e710b5c..39e710b5c 100644
--- a/samples/browseable/BasicContactables/res/values/dimens.xml
+++ b/samples/browseable/BasicAccessibility/res/values/template-dimens.xml
diff --git a/samples/browseable/BasicAccessibility/res/values/styles.xml b/samples/browseable/BasicAccessibility/res/values/template-styles.xml
index 404623e3d..404623e3d 100644
--- a/samples/browseable/BasicAccessibility/res/values/styles.xml
+++ b/samples/browseable/BasicAccessibility/res/values/template-styles.xml
diff --git a/samples/browseable/BasicAndroidKeyStore/res/layout-sw600dp-land/activity_main.xml b/samples/browseable/BasicAndroidKeyStore/res/layout-sw600dp-land/activity_main.xml
new file mode 100644
index 000000000..653454bb2
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/res/layout-sw600dp-land/activity_main.xml
@@ -0,0 +1,37 @@
+<!--
+ Copyright 2013 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.
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:id="@+id/sample_main_layout">
+ <TextView android:id="@+id/sample_output"
+ style="@style/Widget.SampleMessage"
+ android:background="@android:color/white"
+ android:layout_weight="1"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:text="@string/intro_message"
+ android:layout_margin="16dp" />
+ <fragment
+ android:name="com.example.android.common.logger.LogFragment"
+ android:id="@+id/log_fragment"
+ android:layout_weight="1"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_margin="16dp" />
+</LinearLayout>
diff --git a/samples/browseable/BasicAndroidKeyStore/res/layout-sw600dp/activity_main.xml b/samples/browseable/BasicAndroidKeyStore/res/layout-sw600dp/activity_main.xml
new file mode 100644
index 000000000..11cd71b8e
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/res/layout-sw600dp/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+ Copyright 2013 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.
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:id="@+id/sample_main_layout">
+ <TextView android:id="@+id/sample_output"
+ style="@style/Widget.SampleMessage"
+ android:background="@android:color/white"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/intro_message"
+ android:padding="16dp"
+ android:layout_margin="16dp"/>
+ <fragment
+ android:name="com.example.android.common.logger.LogFragment"
+ android:id="@+id/log_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_margin="16dp" />
+</LinearLayout>
diff --git a/samples/browseable/BasicAndroidKeyStore/res/layout/activity_main.xml b/samples/browseable/BasicAndroidKeyStore/res/layout/activity_main.xml
index bc5a57591..6f41369cf 100644
--- a/samples/browseable/BasicAndroidKeyStore/res/layout/activity_main.xml
+++ b/samples/browseable/BasicAndroidKeyStore/res/layout/activity_main.xml
@@ -24,7 +24,8 @@
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:text="@string/intro_message" />
+ android:text="@string/intro_message"
+ android:padding="16dp" />
<View
android:layout_width="fill_parent"
android:layout_height="1dp"
diff --git a/samples/browseable/BasicAndroidKeyStore/res/values-sw600dp/dimens.xml b/samples/browseable/BasicAndroidKeyStore/res/values-sw600dp/template-dimens.xml
index 22074a2bd..22074a2bd 100644
--- a/samples/browseable/BasicAndroidKeyStore/res/values-sw600dp/dimens.xml
+++ b/samples/browseable/BasicAndroidKeyStore/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/BasicAndroidKeyStore/res/values-sw600dp/styles.xml b/samples/browseable/BasicAndroidKeyStore/res/values-sw600dp/template-styles.xml
index 03d197418..03d197418 100644
--- a/samples/browseable/BasicAndroidKeyStore/res/values-sw600dp/styles.xml
+++ b/samples/browseable/BasicAndroidKeyStore/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/BasicGestureDetect/res/values/dimens.xml b/samples/browseable/BasicAndroidKeyStore/res/values/template-dimens.xml
index 39e710b5c..39e710b5c 100644
--- a/samples/browseable/BasicGestureDetect/res/values/dimens.xml
+++ b/samples/browseable/BasicAndroidKeyStore/res/values/template-dimens.xml
diff --git a/samples/browseable/BasicAndroidKeyStore/res/values/template-styles.xml b/samples/browseable/BasicAndroidKeyStore/res/values/template-styles.xml
new file mode 100644
index 000000000..cfffcbd1b
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/res/values/template-styles.xml
@@ -0,0 +1,54 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+ <style name="AppTheme" parent="Theme.Base" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:padding">@dimen/margin_medium</item>
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ <item name="android:layout_margin">16dp</item>
+ <item name="android:shadowDy">-6.5</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+
+ <style name="Widget.SampleOutput">
+ <item name="android:padding">@dimen/margin_medium</item>
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Log" parent="Widget.SampleOutput">
+ <item name="android:typeface">monospace</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/MainActivity.java b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/MainActivity.java
index 9f165655b..7711f3506 100644
--- a/samples/browseable/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/MainActivity.java
+++ b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/MainActivity.java
@@ -19,6 +19,7 @@
package com.example.android.basicandroidkeystore;
+import android.graphics.Color;
import android.os.Bundle;
import android.support.v4.app.FragmentTransaction;
import android.view.Menu;
@@ -72,6 +73,8 @@ public class MainActivity extends SampleActivityBase {
LogFragment logFragment = (LogFragment) getSupportFragmentManager()
.findFragmentById(R.id.log_fragment);
msgFilter.setNext(logFragment.getLogView());
+ logFragment.getLogView().setTextAppearance(this, R.style.Log);
+ logFragment.getLogView().setBackgroundColor(Color.WHITE);
Log.i(TAG, "Ready");
}
diff --git a/samples/browseable/BasicContactables/res/values-sw600dp/dimens.xml b/samples/browseable/BasicContactables/res/values-sw600dp/template-dimens.xml
index 22074a2bd..22074a2bd 100644
--- a/samples/browseable/BasicContactables/res/values-sw600dp/dimens.xml
+++ b/samples/browseable/BasicContactables/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/BasicContactables/res/values-sw600dp/styles.xml b/samples/browseable/BasicContactables/res/values-sw600dp/template-styles.xml
index 03d197418..03d197418 100644
--- a/samples/browseable/BasicContactables/res/values-sw600dp/styles.xml
+++ b/samples/browseable/BasicContactables/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/BasicContactables/res/values/styles.xml b/samples/browseable/BasicContactables/res/values/styles.xml
index 404623e3d..c3a400d85 100644
--- a/samples/browseable/BasicContactables/res/values/styles.xml
+++ b/samples/browseable/BasicContactables/res/values/styles.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2013 The Android Open Source Project
@@ -15,28 +16,12 @@
-->
<resources>
-
- <!-- Activity themes -->
-
- <style name="Theme.Base" parent="android:Theme.Holo.Light" />
-
- <style name="Theme.Sample" parent="Theme.Base" />
-
- <style name="AppTheme" parent="Theme.Sample" />
<!-- Widget styling -->
- <style name="Widget" />
-
- <style name="Widget.SampleMessage">
+ <style name="Widget.SampleOutput">
+ <item name="android:padding">@dimen/margin_medium</item>
<item name="android:textAppearance">?android:textAppearanceMedium</item>
<item name="android:lineSpacingMultiplier">1.1</item>
</style>
- <style name="Widget.SampleMessageTile">
- <item name="android:background">@drawable/tile</item>
- <item name="android:shadowColor">#7F000000</item>
- <item name="android:shadowDy">-3.5</item>
- <item name="android:shadowRadius">2</item>
- </style>
-
</resources>
diff --git a/samples/browseable/BasicImmersiveMode/res/values/dimens.xml b/samples/browseable/BasicContactables/res/values/template-dimens.xml
index 39e710b5c..39e710b5c 100644
--- a/samples/browseable/BasicImmersiveMode/res/values/dimens.xml
+++ b/samples/browseable/BasicContactables/res/values/template-dimens.xml
diff --git a/samples/browseable/BasicMediaDecoder/res/values/styles.xml b/samples/browseable/BasicContactables/res/values/template-styles.xml
index 404623e3d..404623e3d 100644
--- a/samples/browseable/BasicMediaDecoder/res/values/styles.xml
+++ b/samples/browseable/BasicContactables/res/values/template-styles.xml
diff --git a/samples/browseable/BasicGestureDetect/res/values-sw600dp/dimens.xml b/samples/browseable/BasicGestureDetect/res/values-sw600dp/template-dimens.xml
index 22074a2bd..22074a2bd 100644
--- a/samples/browseable/BasicGestureDetect/res/values-sw600dp/dimens.xml
+++ b/samples/browseable/BasicGestureDetect/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/BasicGestureDetect/res/values-sw600dp/styles.xml b/samples/browseable/BasicGestureDetect/res/values-sw600dp/template-styles.xml
index 03d197418..03d197418 100644
--- a/samples/browseable/BasicGestureDetect/res/values-sw600dp/styles.xml
+++ b/samples/browseable/BasicGestureDetect/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/BasicMediaDecoder/res/values/dimens.xml b/samples/browseable/BasicGestureDetect/res/values/template-dimens.xml
index 39e710b5c..39e710b5c 100644
--- a/samples/browseable/BasicMediaDecoder/res/values/dimens.xml
+++ b/samples/browseable/BasicGestureDetect/res/values/template-dimens.xml
diff --git a/samples/browseable/BasicAndroidKeyStore/res/values/styles.xml b/samples/browseable/BasicGestureDetect/res/values/template-styles.xml
index d3f82ff64..d3f82ff64 100644
--- a/samples/browseable/BasicAndroidKeyStore/res/values/styles.xml
+++ b/samples/browseable/BasicGestureDetect/res/values/template-styles.xml
diff --git a/samples/browseable/BasicGestureDetect/src/com.example.android.basicgesturedetect/GestureListener.java b/samples/browseable/BasicGestureDetect/src/com.example.android.basicgesturedetect/GestureListener.java
index c2d2b6fb0..2e2921d46 100644
--- a/samples/browseable/BasicGestureDetect/src/com.example.android.basicgesturedetect/GestureListener.java
+++ b/samples/browseable/BasicGestureDetect/src/com.example.android.basicgesturedetect/GestureListener.java
@@ -42,7 +42,7 @@ public class GestureListener extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
- float distanceY) {
+ float distanceY) {
// User attempted to scroll
Log.i(TAG, "Scroll");
return false;
@@ -50,7 +50,7 @@ public class GestureListener extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
- float velocityY) {
+ float velocityY) {
// Fling event occurred. Notification of this one happens after an "up" event.
Log.i(TAG, "Fling");
return false;
diff --git a/samples/browseable/BasicImmersiveMode/res/values-sw600dp/dimens.xml b/samples/browseable/BasicImmersiveMode/res/values-sw600dp/template-dimens.xml
index 22074a2bd..22074a2bd 100644
--- a/samples/browseable/BasicImmersiveMode/res/values-sw600dp/dimens.xml
+++ b/samples/browseable/BasicImmersiveMode/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/BasicImmersiveMode/res/values-sw600dp/styles.xml b/samples/browseable/BasicImmersiveMode/res/values-sw600dp/template-styles.xml
index 03d197418..03d197418 100644
--- a/samples/browseable/BasicImmersiveMode/res/values-sw600dp/styles.xml
+++ b/samples/browseable/BasicImmersiveMode/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/BasicMediaRouter/res/values/dimens.xml b/samples/browseable/BasicImmersiveMode/res/values/template-dimens.xml
index 39e710b5c..39e710b5c 100644
--- a/samples/browseable/BasicMediaRouter/res/values/dimens.xml
+++ b/samples/browseable/BasicImmersiveMode/res/values/template-dimens.xml
diff --git a/samples/browseable/BasicGestureDetect/res/values/styles.xml b/samples/browseable/BasicImmersiveMode/res/values/template-styles.xml
index d3f82ff64..d3f82ff64 100644
--- a/samples/browseable/BasicGestureDetect/res/values/styles.xml
+++ b/samples/browseable/BasicImmersiveMode/res/values/template-styles.xml
diff --git a/samples/browseable/BasicMediaDecoder/res/values-sw600dp/dimens.xml b/samples/browseable/BasicMediaDecoder/res/values-sw600dp/template-dimens.xml
index 22074a2bd..22074a2bd 100644
--- a/samples/browseable/BasicMediaDecoder/res/values-sw600dp/dimens.xml
+++ b/samples/browseable/BasicMediaDecoder/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/BasicMediaDecoder/res/values-sw600dp/styles.xml b/samples/browseable/BasicMediaDecoder/res/values-sw600dp/template-styles.xml
index 03d197418..03d197418 100644
--- a/samples/browseable/BasicMediaDecoder/res/values-sw600dp/styles.xml
+++ b/samples/browseable/BasicMediaDecoder/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/BasicMultitouch/res/values/dimens.xml b/samples/browseable/BasicMediaDecoder/res/values/template-dimens.xml
index 39e710b5c..39e710b5c 100644
--- a/samples/browseable/BasicMultitouch/res/values/dimens.xml
+++ b/samples/browseable/BasicMediaDecoder/res/values/template-dimens.xml
diff --git a/samples/browseable/BasicNotifications/res/values/styles.xml b/samples/browseable/BasicMediaDecoder/res/values/template-styles.xml
index 404623e3d..404623e3d 100644
--- a/samples/browseable/BasicNotifications/res/values/styles.xml
+++ b/samples/browseable/BasicMediaDecoder/res/values/template-styles.xml
diff --git a/samples/browseable/BasicMediaRouter/res/values-sw600dp/dimens.xml b/samples/browseable/BasicMediaRouter/res/values-sw600dp/template-dimens.xml
index 22074a2bd..22074a2bd 100644
--- a/samples/browseable/BasicMediaRouter/res/values-sw600dp/dimens.xml
+++ b/samples/browseable/BasicMediaRouter/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/BasicMediaRouter/res/values-sw600dp/styles.xml b/samples/browseable/BasicMediaRouter/res/values-sw600dp/template-styles.xml
index 03d197418..03d197418 100644
--- a/samples/browseable/BasicMediaRouter/res/values-sw600dp/styles.xml
+++ b/samples/browseable/BasicMediaRouter/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/BasicMediaRouter/res/values/styles.xml b/samples/browseable/BasicMediaRouter/res/values/styles.xml
index 404623e3d..4f640541c 100644
--- a/samples/browseable/BasicMediaRouter/res/values/styles.xml
+++ b/samples/browseable/BasicMediaRouter/res/values/styles.xml
@@ -1,42 +1,22 @@
-<!--
- Copyright 2013 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<resources>
-
- <!-- Activity themes -->
-
- <style name="Theme.Base" parent="android:Theme.Holo.Light" />
-
- <style name="Theme.Sample" parent="Theme.Base" />
-
- <style name="AppTheme" parent="Theme.Sample" />
- <!-- Widget styling -->
-
- <style name="Widget" />
-
- <style name="Widget.SampleMessage">
- <item name="android:textAppearance">?android:textAppearanceMedium</item>
- <item name="android:lineSpacingMultiplier">1.1</item>
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <!--
+ Base application theme, dependent on API level. This theme is replaced
+ by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Light">
+ <!--
+ Theme customizations available in newer API levels can go in
+ res/values-vXX/styles.xml, while customizations related to
+ backward-compatibility can go here.
+ -->
</style>
- <style name="Widget.SampleMessageTile">
- <item name="android:background">@drawable/tile</item>
- <item name="android:shadowColor">#7F000000</item>
- <item name="android:shadowDy">-3.5</item>
- <item name="android:shadowRadius">2</item>
+
+ <style name="DisplayLargeText">
+ <item name="android:textSize">30sp</item>
+ <item name="android:textStyle">bold</item>
+ <item name="android:textColor">#FFFFFF</item>
</style>
-</resources>
+</resources> \ No newline at end of file
diff --git a/samples/browseable/BasicNetworking/res/values/dimens.xml b/samples/browseable/BasicMediaRouter/res/values/template-dimens.xml
index 39e710b5c..39e710b5c 100644
--- a/samples/browseable/BasicNetworking/res/values/dimens.xml
+++ b/samples/browseable/BasicMediaRouter/res/values/template-dimens.xml
diff --git a/samples/browseable/BasicSyncAdapter/res/values/styles.xml b/samples/browseable/BasicMediaRouter/res/values/template-styles.xml
index 404623e3d..404623e3d 100644
--- a/samples/browseable/BasicSyncAdapter/res/values/styles.xml
+++ b/samples/browseable/BasicMediaRouter/res/values/template-styles.xml
diff --git a/samples/browseable/BasicMultitouch/res/values-sw600dp/dimens.xml b/samples/browseable/BasicMultitouch/res/values-sw600dp/template-dimens.xml
index 22074a2bd..22074a2bd 100644
--- a/samples/browseable/BasicMultitouch/res/values-sw600dp/dimens.xml
+++ b/samples/browseable/BasicMultitouch/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/BasicMultitouch/res/values-sw600dp/styles.xml b/samples/browseable/BasicMultitouch/res/values-sw600dp/template-styles.xml
index 03d197418..03d197418 100644
--- a/samples/browseable/BasicMultitouch/res/values-sw600dp/styles.xml
+++ b/samples/browseable/BasicMultitouch/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/BasicMultitouch/res/values/styles.xml b/samples/browseable/BasicMultitouch/res/values/styles.xml
index 404623e3d..e56d4f86e 100644
--- a/samples/browseable/BasicMultitouch/res/values/styles.xml
+++ b/samples/browseable/BasicMultitouch/res/values/styles.xml
@@ -13,30 +13,18 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
<resources>
- <!-- Activity themes -->
-
- <style name="Theme.Base" parent="android:Theme.Holo.Light" />
-
- <style name="Theme.Sample" parent="Theme.Base" />
-
- <style name="AppTheme" parent="Theme.Sample" />
- <!-- Widget styling -->
-
- <style name="Widget" />
-
- <style name="Widget.SampleMessage">
- <item name="android:textAppearance">?android:textAppearanceMedium</item>
- <item name="android:lineSpacingMultiplier">1.1</item>
- </style>
-
- <style name="Widget.SampleMessageTile">
- <item name="android:background">@drawable/tile</item>
- <item name="android:shadowColor">#7F000000</item>
- <item name="android:shadowDy">-3.5</item>
- <item name="android:shadowRadius">2</item>
+ <!--
+ Base application theme, dependent on API level. This theme is replaced
+ by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Light.NoTitleBar">
+ <!--
+ Theme customizations available in newer API levels can go in
+ res/values-vXX/styles.xml, while customizations related to
+ backward-compatibility can go here.
+ -->
</style>
-</resources>
+</resources> \ No newline at end of file
diff --git a/samples/browseable/BasicNotifications/res/values/dimens.xml b/samples/browseable/BasicMultitouch/res/values/template-dimens.xml
index 39e710b5c..39e710b5c 100644
--- a/samples/browseable/BasicNotifications/res/values/dimens.xml
+++ b/samples/browseable/BasicMultitouch/res/values/template-dimens.xml
diff --git a/samples/browseable/BluetoothLeGatt/res/values/styles.xml b/samples/browseable/BasicMultitouch/res/values/template-styles.xml
index 404623e3d..404623e3d 100644
--- a/samples/browseable/BluetoothLeGatt/res/values/styles.xml
+++ b/samples/browseable/BasicMultitouch/res/values/template-styles.xml
diff --git a/samples/browseable/BasicNetworking/res/values-sw600dp/dimens.xml b/samples/browseable/BasicNetworking/res/values-sw600dp/template-dimens.xml
index 22074a2bd..22074a2bd 100644
--- a/samples/browseable/BasicNetworking/res/values-sw600dp/dimens.xml
+++ b/samples/browseable/BasicNetworking/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/BasicNetworking/res/values-sw600dp/styles.xml b/samples/browseable/BasicNetworking/res/values-sw600dp/template-styles.xml
index 03d197418..03d197418 100644
--- a/samples/browseable/BasicNetworking/res/values-sw600dp/styles.xml
+++ b/samples/browseable/BasicNetworking/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/BasicNetworking/res/values/styles.xml b/samples/browseable/BasicNetworking/res/values/styles.xml
index 404623e3d..3450a54ba 100644
--- a/samples/browseable/BasicNetworking/res/values/styles.xml
+++ b/samples/browseable/BasicNetworking/res/values/styles.xml
@@ -8,7 +8,7 @@
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,
+ distributed under thegi 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.
@@ -16,27 +16,17 @@
<resources>
- <!-- Activity themes -->
-
- <style name="Theme.Base" parent="android:Theme.Holo.Light" />
-
- <style name="Theme.Sample" parent="Theme.Base" />
-
- <style name="AppTheme" parent="Theme.Sample" />
<!-- Widget styling -->
- <style name="Widget" />
-
- <style name="Widget.SampleMessage">
+ <style name="Widget.SampleOutput">
+ <item name="android:padding">@dimen/margin_medium</item>
<item name="android:textAppearance">?android:textAppearanceMedium</item>
<item name="android:lineSpacingMultiplier">1.1</item>
</style>
- <style name="Widget.SampleMessageTile">
- <item name="android:background">@drawable/tile</item>
- <item name="android:shadowColor">#7F000000</item>
- <item name="android:shadowDy">-3.5</item>
- <item name="android:shadowRadius">2</item>
+ <style name="Log" parent="Widget.SampleOutput">
+ <item name="android:typeface">monospace</item>
</style>
+
</resources>
diff --git a/samples/browseable/BasicSyncAdapter/res/values/dimens.xml b/samples/browseable/BasicNetworking/res/values/template-dimens.xml
index 39e710b5c..39e710b5c 100644
--- a/samples/browseable/BasicSyncAdapter/res/values/dimens.xml
+++ b/samples/browseable/BasicNetworking/res/values/template-dimens.xml
diff --git a/samples/browseable/HorizontalPaging/res/values/styles.xml b/samples/browseable/BasicNetworking/res/values/template-styles.xml
index 404623e3d..404623e3d 100644
--- a/samples/browseable/HorizontalPaging/res/values/styles.xml
+++ b/samples/browseable/BasicNetworking/res/values/template-styles.xml
diff --git a/samples/browseable/BasicNotifications/res/values-sw600dp/dimens.xml b/samples/browseable/BasicNotifications/res/values-sw600dp/template-dimens.xml
index 22074a2bd..22074a2bd 100644
--- a/samples/browseable/BasicNotifications/res/values-sw600dp/dimens.xml
+++ b/samples/browseable/BasicNotifications/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/BasicNotifications/res/values-sw600dp/styles.xml b/samples/browseable/BasicNotifications/res/values-sw600dp/template-styles.xml
index 03d197418..03d197418 100644
--- a/samples/browseable/BasicNotifications/res/values-sw600dp/styles.xml
+++ b/samples/browseable/BasicNotifications/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/BluetoothLeGatt/res/values/dimens.xml b/samples/browseable/BasicNotifications/res/values/template-dimens.xml
index 39e710b5c..39e710b5c 100644
--- a/samples/browseable/BluetoothLeGatt/res/values/dimens.xml
+++ b/samples/browseable/BasicNotifications/res/values/template-dimens.xml
diff --git a/samples/browseable/NetworkConnect/res/values/styles.xml b/samples/browseable/BasicNotifications/res/values/template-styles.xml
index 404623e3d..404623e3d 100644
--- a/samples/browseable/NetworkConnect/res/values/styles.xml
+++ b/samples/browseable/BasicNotifications/res/values/template-styles.xml
diff --git a/samples/browseable/BasicRenderScript/AndroidManifest.xml b/samples/browseable/BasicRenderScript/AndroidManifest.xml
new file mode 100644
index 000000000..e1e2dfc1b
--- /dev/null
+++ b/samples/browseable/BasicRenderScript/AndroidManifest.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+ Copyright 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.basicrenderscript"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <uses-sdk
+ android:minSdkVersion="8"
+ android:targetSdkVersion="19" />
+
+ <application
+ android:allowBackup="true"
+ android:label="@string/app_name"
+ android:icon="@drawable/ic_launcher"
+ android:theme="@style/AppTheme">
+
+ <activity
+ android:name=".MainActivity"
+ android:label="@string/app_name"
+ android:theme="@style/FullscreenTheme">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+
+</manifest>
diff --git a/samples/browseable/BasicRenderScript/_index.jd b/samples/browseable/BasicRenderScript/_index.jd
new file mode 100644
index 000000000..9c0f029b3
--- /dev/null
+++ b/samples/browseable/BasicRenderScript/_index.jd
@@ -0,0 +1,13 @@
+
+
+
+page.tags="BasicRenderScript"
+sample.group=RenderScript
+@jd:body
+
+<p>
+
+ BasicRenderScript sample demonstrates basic steps how to use renderScript.
+ In the sample, it performs graphical filter operation on a image with renderScript.
+
+ </p>
diff --git a/samples/browseable/BasicRenderScript/res/drawable-hdpi/ic_launcher.png b/samples/browseable/BasicRenderScript/res/drawable-hdpi/ic_launcher.png
new file mode 100755
index 000000000..75b3c9781
--- /dev/null
+++ b/samples/browseable/BasicRenderScript/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/repeatingAlarm/res/drawable-hdpi/tile.9.png b/samples/browseable/BasicRenderScript/res/drawable-hdpi/tile.9.png
index 135862883..135862883 100644
--- a/samples/browseable/repeatingAlarm/res/drawable-hdpi/tile.9.png
+++ b/samples/browseable/BasicRenderScript/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/BasicRenderScript/res/drawable-mdpi/ic_launcher.png b/samples/browseable/BasicRenderScript/res/drawable-mdpi/ic_launcher.png
new file mode 100755
index 000000000..4ccd98e09
--- /dev/null
+++ b/samples/browseable/BasicRenderScript/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicRenderScript/res/drawable-nodpi/data.jpg b/samples/browseable/BasicRenderScript/res/drawable-nodpi/data.jpg
new file mode 100644
index 000000000..81a87b172
--- /dev/null
+++ b/samples/browseable/BasicRenderScript/res/drawable-nodpi/data.jpg
Binary files differ
diff --git a/samples/browseable/BasicRenderScript/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/BasicRenderScript/res/drawable-xhdpi/ic_launcher.png
new file mode 100755
index 000000000..7c5aeed04
--- /dev/null
+++ b/samples/browseable/BasicRenderScript/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicRenderScript/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/BasicRenderScript/res/drawable-xxhdpi/ic_launcher.png
new file mode 100755
index 000000000..3c45f511e
--- /dev/null
+++ b/samples/browseable/BasicRenderScript/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicRenderScript/res/layout/activity_main.xml b/samples/browseable/BasicRenderScript/res/layout/activity_main.xml
new file mode 100755
index 000000000..be1aa49d9
--- /dev/null
+++ b/samples/browseable/BasicRenderScript/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+ Copyright 2013 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.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <LinearLayout style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/horizontal_page_margin"
+ android:layout_marginRight="@dimen/horizontal_page_margin"
+ android:layout_marginTop="@dimen/vertical_page_margin"
+ android:layout_marginBottom="@dimen/vertical_page_margin"
+ android:text="@string/intro_message" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/BasicRenderScript/res/layout/main_layout.xml b/samples/browseable/BasicRenderScript/res/layout/main_layout.xml
new file mode 100644
index 000000000..69695f07b
--- /dev/null
+++ b/samples/browseable/BasicRenderScript/res/layout/main_layout.xml
@@ -0,0 +1,22 @@
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="#0099cc"
+ tools:context=".MainActivity">
+
+ <ImageView
+ android:id="@+id/imageView"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scaleType="fitCenter"
+ android:src="@drawable/data" />
+
+ <SeekBar
+ android:id="@+id/seekBar1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom"
+ android:layout_marginBottom="16dp" />
+
+</FrameLayout>
diff --git a/samples/browseable/BasicSyncAdapter/res/values-sw600dp/dimens.xml b/samples/browseable/BasicRenderScript/res/values-sw600dp/template-dimens.xml
index 22074a2bd..22074a2bd 100644
--- a/samples/browseable/BasicSyncAdapter/res/values-sw600dp/dimens.xml
+++ b/samples/browseable/BasicRenderScript/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/BasicSyncAdapter/res/values-sw600dp/styles.xml b/samples/browseable/BasicRenderScript/res/values-sw600dp/template-styles.xml
index 03d197418..03d197418 100644
--- a/samples/browseable/BasicSyncAdapter/res/values-sw600dp/styles.xml
+++ b/samples/browseable/BasicRenderScript/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/BasicRenderScript/res/values-v11/styles.xml b/samples/browseable/BasicRenderScript/res/values-v11/styles.xml
new file mode 100644
index 000000000..f3a90c687
--- /dev/null
+++ b/samples/browseable/BasicRenderScript/res/values-v11/styles.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!--
+ Base application theme for API 11+. This theme completely replaces
+ AppBaseTheme from res/values/styles.xml on API 11+ devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Holo.Light">
+ <!-- API 11 theme customizations can go here. -->
+ </style>
+
+ <style name="FullscreenTheme" parent="android:Theme.Holo">
+ <item name="android:actionBarStyle">@style/FullscreenActionBarStyle</item>
+ <item name="android:windowActionBarOverlay">true</item>
+ <item name="android:windowBackground">@null</item>
+ <item name="buttonBarStyle">?android:attr/buttonBarStyle</item>
+ <item name="buttonBarButtonStyle">?android:attr/buttonBarButtonStyle</item>
+ </style>
+
+ <style name="FullscreenActionBarStyle" parent="android:Widget.Holo.ActionBar">
+ <item name="android:background">@color/black_overlay</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/BasicRenderScript/res/values-v14/styles.xml b/samples/browseable/BasicRenderScript/res/values-v14/styles.xml
new file mode 100644
index 000000000..a91fd0372
--- /dev/null
+++ b/samples/browseable/BasicRenderScript/res/values-v14/styles.xml
@@ -0,0 +1,12 @@
+<resources>
+
+ <!--
+ Base application theme for API 14+. This theme completely replaces
+ AppBaseTheme from BOTH res/values/styles.xml and
+ res/values-v11/styles.xml on API 14+ devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
+ <!-- API 14 theme customizations can go here. -->
+ </style>
+
+</resources>
diff --git a/samples/browseable/BasicRenderScript/res/values/attrs.xml b/samples/browseable/BasicRenderScript/res/values/attrs.xml
new file mode 100644
index 000000000..e67df0a37
--- /dev/null
+++ b/samples/browseable/BasicRenderScript/res/values/attrs.xml
@@ -0,0 +1,14 @@
+<resources>
+
+ <!--
+ Declare custom theme attributes that allow changing which styles are
+ used for button bars depending on the API level.
+ ?android:attr/buttonBarStyle is new as of API 11 so this is
+ necessary to support previous API levels.
+ -->
+ <declare-styleable name="ButtonBarContainerTheme">
+ <attr name="buttonBarStyle" format="reference" />
+ <attr name="buttonBarButtonStyle" format="reference" />
+ </declare-styleable>
+
+</resources>
diff --git a/samples/browseable/BasicRenderScript/res/values/base-strings.xml b/samples/browseable/BasicRenderScript/res/values/base-strings.xml
new file mode 100644
index 000000000..a35b3206f
--- /dev/null
+++ b/samples/browseable/BasicRenderScript/res/values/base-strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+ <string name="app_name">BasicRenderScript</string>
+ <string name="intro_message">
+ <![CDATA[
+
+
+ BasicRenderScript sample demonstrates basic steps how to use renderScript.
+ In the sample, it performs graphical filter operation on a image with renderScript.
+
+
+ ]]>
+ </string>
+</resources>
diff --git a/samples/browseable/BasicRenderScript/res/values/colors.xml b/samples/browseable/BasicRenderScript/res/values/colors.xml
new file mode 100644
index 000000000..327c0604c
--- /dev/null
+++ b/samples/browseable/BasicRenderScript/res/values/colors.xml
@@ -0,0 +1,5 @@
+<resources>
+
+ <color name="black_overlay">#66000000</color>
+
+</resources>
diff --git a/samples/browseable/BasicRenderScript/res/values/styles.xml b/samples/browseable/BasicRenderScript/res/values/styles.xml
new file mode 100644
index 000000000..49299b98a
--- /dev/null
+++ b/samples/browseable/BasicRenderScript/res/values/styles.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+
+ <style name="FullscreenTheme" parent="android:Theme.NoTitleBar">
+ <item name="android:windowContentOverlay">@null</item>
+ <item name="android:windowBackground">@null</item>
+ <item name="buttonBarStyle">@style/ButtonBar</item>
+ <item name="buttonBarButtonStyle">@style/ButtonBarButton</item>
+ </style>
+
+ <style name="ButtonBar">
+ <item name="android:paddingLeft">2dp</item>
+ <item name="android:paddingTop">5dp</item>
+ <item name="android:paddingRight">2dp</item>
+ <item name="android:paddingBottom">0dp</item>
+ <item name="android:background">@android:drawable/bottom_bar</item>
+ </style>
+
+ <style name="ButtonBarButton" />
+
+</resources>
diff --git a/samples/browseable/DoneBar/res/values/dimens.xml b/samples/browseable/BasicRenderScript/res/values/template-dimens.xml
index 39e710b5c..39e710b5c 100644
--- a/samples/browseable/DoneBar/res/values/dimens.xml
+++ b/samples/browseable/BasicRenderScript/res/values/template-dimens.xml
diff --git a/samples/browseable/TextSwitcher/res/values/styles.xml b/samples/browseable/BasicRenderScript/res/values/template-styles.xml
index 404623e3d..404623e3d 100644
--- a/samples/browseable/TextSwitcher/res/values/styles.xml
+++ b/samples/browseable/BasicRenderScript/res/values/template-styles.xml
diff --git a/samples/browseable/BasicRenderScript/src/com.example.android.basicrenderscript/MainActivity.java b/samples/browseable/BasicRenderScript/src/com.example.android.basicrenderscript/MainActivity.java
new file mode 100644
index 000000000..ed6d5ad14
--- /dev/null
+++ b/samples/browseable/BasicRenderScript/src/com.example.android.basicrenderscript/MainActivity.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.basicrenderscript;
+
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.widget.ImageView;
+import android.widget.SeekBar;
+import android.widget.SeekBar.OnSeekBarChangeListener;
+import android.support.v8.renderscript.*;
+
+public class MainActivity extends Activity {
+ /* Number of bitmaps that is used for renderScript thread and UI thread synchronization.
+ Ideally, this can be reduced to 2, however in some devices, 2 buffers still showing tierings on UI.
+ Investigating a root cause.
+ */
+ private final int NUM_BITMAPS = 3;
+ private int mCurrentBitmap = 0;
+ private Bitmap mBitmapIn;
+ private Bitmap[] mBitmapsOut;
+ private ImageView mImageView;
+
+ private RenderScript mRS;
+ private Allocation mInAllocation;
+ private Allocation[] mOutAllocations;
+ private ScriptC_saturation mScript;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.main_layout);
+
+ /*
+ * Initialize UI
+ */
+ mBitmapIn = loadBitmap(R.drawable.data);
+ mBitmapsOut = new Bitmap[NUM_BITMAPS];
+ for (int i = 0; i < NUM_BITMAPS; ++i) {
+ mBitmapsOut[i] = Bitmap.createBitmap(mBitmapIn.getWidth(),
+ mBitmapIn.getHeight(), mBitmapIn.getConfig());
+ }
+
+ mImageView = (ImageView) findViewById(R.id.imageView);
+ mImageView.setImageBitmap(mBitmapsOut[mCurrentBitmap]);
+ mCurrentBitmap += (mCurrentBitmap + 1) % NUM_BITMAPS;
+
+ SeekBar seekbar = (SeekBar) findViewById(R.id.seekBar1);
+ seekbar.setProgress(50);
+ seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
+ public void onProgressChanged(SeekBar seekBar, int progress,
+ boolean fromUser) {
+ float max = 2.0f;
+ float min = 0.0f;
+ float f = (float) ((max - min) * (progress / 100.0) + min);
+ updateImage(f);
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ }
+ });
+
+ /*
+ * Create renderScript
+ */
+ createScript();
+
+ /*
+ * Invoke renderScript kernel and update imageView
+ */
+ updateImage(1.0f);
+ }
+
+ /*
+ * Initialize RenderScript
+ * In the sample, it creates RenderScript kernel that performs saturation manipulation.
+ */
+ private void createScript() {
+ //Initialize RS
+ mRS = RenderScript.create(this);
+
+ //Allocate buffers
+ mInAllocation = Allocation.createFromBitmap(mRS, mBitmapIn);
+ mOutAllocations = new Allocation[NUM_BITMAPS];
+ for (int i = 0; i < NUM_BITMAPS; ++i) {
+ mOutAllocations[i] = Allocation.createFromBitmap(mRS, mBitmapsOut[i]);
+ }
+
+ //Load script
+ mScript = new ScriptC_saturation(mRS);
+ }
+
+ /*
+ * In the AsyncTask, it invokes RenderScript intrinsics to do a filtering.
+ * After the filtering is done, an operation blocks at Allication.copyTo() in AsyncTask thread.
+ * Once all operation is finished at onPostExecute() in UI thread, it can invalidate and update ImageView UI.
+ */
+ private class RenderScriptTask extends AsyncTask<Float, Integer, Integer> {
+ Boolean issued = false;
+
+ protected Integer doInBackground(Float... values) {
+ int index = -1;
+ if (isCancelled() == false) {
+ issued = true;
+ index = mCurrentBitmap;
+
+ /*
+ * Set global variable in RS
+ */
+ mScript.set_saturationValue(values[0]);
+
+ /*
+ * Invoke saturation filter kernel
+ */
+ mScript.forEach_saturation(mInAllocation, mOutAllocations[index]);
+
+ /*
+ * Copy to bitmap and invalidate image view
+ */
+ mOutAllocations[index].copyTo(mBitmapsOut[index]);
+ mCurrentBitmap = (mCurrentBitmap + 1) % NUM_BITMAPS;
+ }
+ return index;
+ }
+
+ void updateView(Integer result) {
+ if (result != -1) {
+ // Request UI update
+ mImageView.setImageBitmap(mBitmapsOut[result]);
+ mImageView.invalidate();
+ }
+ }
+
+ protected void onPostExecute(Integer result) {
+ updateView(result);
+ }
+
+ protected void onCancelled(Integer result) {
+ if (issued) {
+ updateView(result);
+ }
+ }
+ }
+
+ RenderScriptTask currentTask = null;
+
+ /*
+ Invoke AsynchTask and cancel previous task.
+ When AsyncTasks are piled up (typically in slow device with heavy kernel),
+ Only the latest (and already started) task invokes RenderScript operation.
+ */
+ private void updateImage(final float f) {
+ if (currentTask != null)
+ currentTask.cancel(false);
+ currentTask = new RenderScriptTask();
+ currentTask.execute(f);
+ }
+
+ /*
+ Helper to load Bitmap from resource
+ */
+ private Bitmap loadBitmap(int resource) {
+ final BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inPreferredConfig = Bitmap.Config.ARGB_8888;
+ return BitmapFactory.decodeResource(getResources(), resource, options);
+ }
+
+}
diff --git a/samples/browseable/BasicRenderScript/src/com.example.android.common.media/CameraHelper.java b/samples/browseable/BasicRenderScript/src/com.example.android.common.media/CameraHelper.java
new file mode 100644
index 000000000..1fa841675
--- /dev/null
+++ b/samples/browseable/BasicRenderScript/src/com.example.android.common.media/CameraHelper.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2013 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.example.android.common.media;
+
+import android.annotation.TargetApi;
+import android.hardware.Camera;
+import android.os.Build;
+import android.os.Environment;
+import android.util.Log;
+
+import java.io.File;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Camera related utilities.
+ */
+public class CameraHelper {
+
+ public static final int MEDIA_TYPE_IMAGE = 1;
+ public static final int MEDIA_TYPE_VIDEO = 2;
+
+ /**
+ * Iterate over supported camera preview sizes to see which one best fits the
+ * dimensions of the given view while maintaining the aspect ratio. If none can,
+ * be lenient with the aspect ratio.
+ *
+ * @param sizes Supported camera preview sizes.
+ * @param w The width of the view.
+ * @param h The height of the view.
+ * @return Best match camera preview size to fit in the view.
+ */
+ public static Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
+ // Use a very small tolerance because we want an exact match.
+ final double ASPECT_TOLERANCE = 0.1;
+ double targetRatio = (double) w / h;
+ if (sizes == null)
+ return null;
+
+ Camera.Size optimalSize = null;
+
+ // Start with max value and refine as we iterate over available preview sizes. This is the
+ // minimum difference between view and camera height.
+ double minDiff = Double.MAX_VALUE;
+
+ // Target view height
+ int targetHeight = h;
+
+ // Try to find a preview size that matches aspect ratio and the target view size.
+ // Iterate over all available sizes and pick the largest size that can fit in the view and
+ // still maintain the aspect ratio.
+ for (Camera.Size size : sizes) {
+ double ratio = (double) size.width / size.height;
+ if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
+ continue;
+ if (Math.abs(size.height - targetHeight) < minDiff) {
+ optimalSize = size;
+ minDiff = Math.abs(size.height - targetHeight);
+ }
+ }
+
+ // Cannot find preview size that matches the aspect ratio, ignore the requirement
+ if (optimalSize == null) {
+ minDiff = Double.MAX_VALUE;
+ for (Camera.Size size : sizes) {
+ if (Math.abs(size.height - targetHeight) < minDiff) {
+ optimalSize = size;
+ minDiff = Math.abs(size.height - targetHeight);
+ }
+ }
+ }
+ return optimalSize;
+ }
+
+ /**
+ * @return the default camera on the device. Return null if there is no camera on the device.
+ */
+ public static Camera getDefaultCameraInstance() {
+ return Camera.open();
+ }
+
+
+ /**
+ * @return the default rear/back facing camera on the device. Returns null if camera is not
+ * available.
+ */
+ public static Camera getDefaultBackFacingCameraInstance() {
+ return getDefaultCamera(Camera.CameraInfo.CAMERA_FACING_BACK);
+ }
+
+ /**
+ * @return the default front facing camera on the device. Returns null if camera is not
+ * available.
+ */
+ public static Camera getDefaultFrontFacingCameraInstance() {
+ return getDefaultCamera(Camera.CameraInfo.CAMERA_FACING_FRONT);
+ }
+
+
+ /**
+ *
+ * @param position Physical position of the camera i.e Camera.CameraInfo.CAMERA_FACING_FRONT
+ * or Camera.CameraInfo.CAMERA_FACING_BACK.
+ * @return the default camera on the device. Returns null if camera is not available.
+ */
+ @TargetApi(Build.VERSION_CODES.GINGERBREAD)
+ private static Camera getDefaultCamera(int position) {
+ // Find the total number of cameras available
+ int mNumberOfCameras = Camera.getNumberOfCameras();
+
+ // Find the ID of the back-facing ("default") camera
+ Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
+ for (int i = 0; i < mNumberOfCameras; i++) {
+ Camera.getCameraInfo(i, cameraInfo);
+ if (cameraInfo.facing == position) {
+ return Camera.open(i);
+
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Creates a media file in the {@code Environment.DIRECTORY_PICTURES} directory. The directory
+ * is persistent and available to other applications like gallery.
+ *
+ * @param type Media type. Can be video or image.
+ * @return A file object pointing to the newly created file.
+ */
+ public static File getOutputMediaFile(int type){
+ // To be safe, you should check that the SDCard is mounted
+ // using Environment.getExternalStorageState() before doing this.
+ if (!Environment.getExternalStorageState().equalsIgnoreCase(Environment.MEDIA_MOUNTED)) {
+ return null;
+ }
+
+ File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
+ Environment.DIRECTORY_PICTURES), "CameraSample");
+ // This location works best if you want the created images to be shared
+ // between applications and persist after your app has been uninstalled.
+
+ // Create the storage directory if it does not exist
+ if (! mediaStorageDir.exists()){
+ if (! mediaStorageDir.mkdirs()) {
+ Log.d("CameraSample", "failed to create directory");
+ return null;
+ }
+ }
+
+ // Create a media file name
+ String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
+ File mediaFile;
+ if (type == MEDIA_TYPE_IMAGE){
+ mediaFile = new File(mediaStorageDir.getPath() + File.separator +
+ "IMG_"+ timeStamp + ".jpg");
+ } else if(type == MEDIA_TYPE_VIDEO) {
+ mediaFile = new File(mediaStorageDir.getPath() + File.separator +
+ "VID_"+ timeStamp + ".mp4");
+ } else {
+ return null;
+ }
+
+ return mediaFile;
+ }
+
+}
diff --git a/samples/browseable/BasicRenderScript/src/com.example.android.common.media/MediaCodecWrapper.java b/samples/browseable/BasicRenderScript/src/com.example.android.common.media/MediaCodecWrapper.java
new file mode 100644
index 000000000..a511221f5
--- /dev/null
+++ b/samples/browseable/BasicRenderScript/src/com.example.android.common.media/MediaCodecWrapper.java
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2013 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.example.android.common.media;
+
+import android.media.*;
+import android.os.Handler;
+import android.os.Looper;
+import android.view.Surface;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayDeque;
+import java.util.Queue;
+
+/**
+ * Simplifies the MediaCodec interface by wrapping around the buffer processing operations.
+ */
+public class MediaCodecWrapper {
+
+ // Handler to use for {@code OutputSampleListener} and {code OutputFormatChangedListener}
+ // callbacks
+ private Handler mHandler;
+
+
+ // Callback when media output format changes.
+ public interface OutputFormatChangedListener {
+ void outputFormatChanged(MediaCodecWrapper sender, MediaFormat newFormat);
+ }
+
+ private OutputFormatChangedListener mOutputFormatChangedListener = null;
+
+ /**
+ * Callback for decodes frames. Observers can register a listener for optional stream
+ * of decoded data
+ */
+ public interface OutputSampleListener {
+ void outputSample(MediaCodecWrapper sender, MediaCodec.BufferInfo info, ByteBuffer buffer);
+ }
+
+ /**
+ * The {@link MediaCodec} that is managed by this class.
+ */
+ private MediaCodec mDecoder;
+
+ // References to the internal buffers managed by the codec. The codec
+ // refers to these buffers by index, never by reference so it's up to us
+ // to keep track of which buffer is which.
+ private ByteBuffer[] mInputBuffers;
+ private ByteBuffer[] mOutputBuffers;
+
+ // Indices of the input buffers that are currently available for writing. We'll
+ // consume these in the order they were dequeued from the codec.
+ private Queue<Integer> mAvailableInputBuffers;
+
+ // Indices of the output buffers that currently hold valid data, in the order
+ // they were produced by the codec.
+ private Queue<Integer> mAvailableOutputBuffers;
+
+ // Information about each output buffer, by index. Each entry in this array
+ // is valid if and only if its index is currently contained in mAvailableOutputBuffers.
+ private MediaCodec.BufferInfo[] mOutputBufferInfo;
+
+ // An (optional) stream that will receive decoded data.
+ private OutputSampleListener mOutputSampleListener;
+
+ private MediaCodecWrapper(MediaCodec codec) {
+ mDecoder = codec;
+ codec.start();
+ mInputBuffers = codec.getInputBuffers();
+ mOutputBuffers = codec.getOutputBuffers();
+ mOutputBufferInfo = new MediaCodec.BufferInfo[mOutputBuffers.length];
+ mAvailableInputBuffers = new ArrayDeque<Integer>(mOutputBuffers.length);
+ mAvailableOutputBuffers = new ArrayDeque<Integer>(mInputBuffers.length);
+ }
+
+ /**
+ * Releases resources and ends the encoding/decoding session.
+ */
+ public void stopAndRelease() {
+ mDecoder.stop();
+ mDecoder.release();
+ mDecoder = null;
+ mHandler = null;
+ }
+
+ /**
+ * Getter for the registered {@link OutputFormatChangedListener}
+ */
+ public OutputFormatChangedListener getOutputFormatChangedListener() {
+ return mOutputFormatChangedListener;
+ }
+
+ /**
+ *
+ * @param outputFormatChangedListener the listener for callback.
+ * @param handler message handler for posting the callback.
+ */
+ public void setOutputFormatChangedListener(final OutputFormatChangedListener
+ outputFormatChangedListener, Handler handler) {
+ mOutputFormatChangedListener = outputFormatChangedListener;
+
+ // Making sure we don't block ourselves due to a bad implementation of the callback by
+ // using a handler provided by client.
+ Looper looper;
+ mHandler = handler;
+ if (outputFormatChangedListener != null && mHandler == null) {
+ if ((looper = Looper.myLooper()) != null) {
+ mHandler = new Handler();
+ } else {
+ throw new IllegalArgumentException(
+ "Looper doesn't exist in the calling thread");
+ }
+ }
+ }
+
+ /**
+ * Constructs the {@link MediaCodecWrapper} wrapper object around the video codec.
+ * The codec is created using the encapsulated information in the
+ * {@link MediaFormat} object.
+ *
+ * @param trackFormat The format of the media object to be decoded.
+ * @param surface Surface to render the decoded frames.
+ * @return
+ */
+ public static MediaCodecWrapper fromVideoFormat(final MediaFormat trackFormat,
+ Surface surface) {
+ MediaCodecWrapper result = null;
+ MediaCodec videoCodec = null;
+
+ // BEGIN_INCLUDE(create_codec)
+ final String mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
+
+ // Check to see if this is actually a video mime type. If it is, then create
+ // a codec that can decode this mime type.
+ if (mimeType.contains("video/")) {
+ videoCodec = MediaCodec.createDecoderByType(mimeType);
+ videoCodec.configure(trackFormat, surface, null, 0);
+
+ }
+
+ // If codec creation was successful, then create a wrapper object around the
+ // newly created codec.
+ if (videoCodec != null) {
+ result = new MediaCodecWrapper(videoCodec);
+ }
+ // END_INCLUDE(create_codec)
+
+ return result;
+ }
+
+
+ /**
+ * Write a media sample to the decoder.
+ *
+ * A "sample" here refers to a single atomic access unit in the media stream. The definition
+ * of "access unit" is dependent on the type of encoding used, but it typically refers to
+ * a single frame of video or a few seconds of audio. {@link android.media.MediaExtractor}
+ * extracts data from a stream one sample at a time.
+ *
+ * @param input A ByteBuffer containing the input data for one sample. The buffer must be set
+ * up for reading, with its position set to the beginning of the sample data and its limit
+ * set to the end of the sample data.
+ *
+ * @param presentationTimeUs The time, relative to the beginning of the media stream,
+ * at which this buffer should be rendered.
+ *
+ * @param flags Flags to pass to the decoder. See {@link MediaCodec#queueInputBuffer(int,
+ * int, int, long, int)}
+ *
+ * @throws MediaCodec.CryptoException
+ */
+ public boolean writeSample(final ByteBuffer input,
+ final MediaCodec.CryptoInfo crypto,
+ final long presentationTimeUs,
+ final int flags) throws MediaCodec.CryptoException, WriteException {
+ boolean result = false;
+ int size = input.remaining();
+
+ // check if we have dequed input buffers available from the codec
+ if (size > 0 && !mAvailableInputBuffers.isEmpty()) {
+ int index = mAvailableInputBuffers.remove();
+ ByteBuffer buffer = mInputBuffers[index];
+
+ // we can't write our sample to a lesser capacity input buffer.
+ if (size > buffer.capacity()) {
+ throw new MediaCodecWrapper.WriteException(String.format(
+ "Insufficient capacity in MediaCodec buffer: "
+ + "tried to write %d, buffer capacity is %d.",
+ input.remaining(),
+ buffer.capacity()));
+ }
+
+ buffer.clear();
+ buffer.put(input);
+
+ // Submit the buffer to the codec for decoding. The presentationTimeUs
+ // indicates the position (play time) for the current sample.
+ if (crypto == null) {
+ mDecoder.queueInputBuffer(index, 0, size, presentationTimeUs, flags);
+ } else {
+ mDecoder.queueSecureInputBuffer(index, 0, crypto, presentationTimeUs, flags);
+ }
+ result = true;
+ }
+ return result;
+ }
+
+ static MediaCodec.CryptoInfo cryptoInfo= new MediaCodec.CryptoInfo();
+
+ /**
+ * Write a media sample to the decoder.
+ *
+ * A "sample" here refers to a single atomic access unit in the media stream. The definition
+ * of "access unit" is dependent on the type of encoding used, but it typically refers to
+ * a single frame of video or a few seconds of audio. {@link android.media.MediaExtractor}
+ * extracts data from a stream one sample at a time.
+ *
+ * @param extractor Instance of {@link android.media.MediaExtractor} wrapping the media.
+ *
+ * @param presentationTimeUs The time, relative to the beginning of the media stream,
+ * at which this buffer should be rendered.
+ *
+ * @param flags Flags to pass to the decoder. See {@link MediaCodec#queueInputBuffer(int,
+ * int, int, long, int)}
+ *
+ * @throws MediaCodec.CryptoException
+ */
+ public boolean writeSample(final MediaExtractor extractor,
+ final boolean isSecure,
+ final long presentationTimeUs,
+ int flags) {
+ boolean result = false;
+ boolean isEos = false;
+
+ if (!mAvailableInputBuffers.isEmpty()) {
+ int index = mAvailableInputBuffers.remove();
+ ByteBuffer buffer = mInputBuffers[index];
+
+ // reads the sample from the file using extractor into the buffer
+ int size = extractor.readSampleData(buffer, 0);
+ if (size <= 0) {
+ flags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
+ }
+
+ // Submit the buffer to the codec for decoding. The presentationTimeUs
+ // indicates the position (play time) for the current sample.
+ if (!isSecure) {
+ mDecoder.queueInputBuffer(index, 0, size, presentationTimeUs, flags);
+ } else {
+ extractor.getSampleCryptoInfo(cryptoInfo);
+ mDecoder.queueSecureInputBuffer(index, 0, cryptoInfo, presentationTimeUs, flags);
+ }
+
+ result = true;
+ }
+ return result;
+ }
+
+ /**
+ * Performs a peek() operation in the queue to extract media info for the buffer ready to be
+ * released i.e. the head element of the queue.
+ *
+ * @param out_bufferInfo An output var to hold the buffer info.
+ *
+ * @return True, if the peek was successful.
+ */
+ public boolean peekSample(MediaCodec.BufferInfo out_bufferInfo) {
+ // dequeue available buffers and synchronize our data structures with the codec.
+ update();
+ boolean result = false;
+ if (!mAvailableOutputBuffers.isEmpty()) {
+ int index = mAvailableOutputBuffers.peek();
+ MediaCodec.BufferInfo info = mOutputBufferInfo[index];
+ // metadata of the sample
+ out_bufferInfo.set(
+ info.offset,
+ info.size,
+ info.presentationTimeUs,
+ info.flags);
+ result = true;
+ }
+ return result;
+ }
+
+ /**
+ * Processes, releases and optionally renders the output buffer available at the head of the
+ * queue. All observers are notified with a callback. See {@link
+ * OutputSampleListener#outputSample(MediaCodecWrapper, android.media.MediaCodec.BufferInfo,
+ * java.nio.ByteBuffer)}
+ *
+ * @param render True, if the buffer is to be rendered on the {@link Surface} configured
+ *
+ */
+ public void popSample(boolean render) {
+ // dequeue available buffers and synchronize our data structures with the codec.
+ update();
+ if (!mAvailableOutputBuffers.isEmpty()) {
+ int index = mAvailableOutputBuffers.remove();
+
+ if (render && mOutputSampleListener != null) {
+ ByteBuffer buffer = mOutputBuffers[index];
+ MediaCodec.BufferInfo info = mOutputBufferInfo[index];
+ mOutputSampleListener.outputSample(this, info, buffer);
+ }
+
+ // releases the buffer back to the codec
+ mDecoder.releaseOutputBuffer(index, render);
+ }
+ }
+
+ /**
+ * Synchronize this object's state with the internal state of the wrapped
+ * MediaCodec.
+ */
+ private void update() {
+ // BEGIN_INCLUDE(update_codec_state)
+ int index;
+
+ // Get valid input buffers from the codec to fill later in the same order they were
+ // made available by the codec.
+ while ((index = mDecoder.dequeueInputBuffer(0)) != MediaCodec.INFO_TRY_AGAIN_LATER) {
+ mAvailableInputBuffers.add(index);
+ }
+
+
+ // Likewise with output buffers. If the output buffers have changed, start using the
+ // new set of output buffers. If the output format has changed, notify listeners.
+ MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
+ while ((index = mDecoder.dequeueOutputBuffer(info, 0)) != MediaCodec.INFO_TRY_AGAIN_LATER) {
+ switch (index) {
+ case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
+ mOutputBuffers = mDecoder.getOutputBuffers();
+ mOutputBufferInfo = new MediaCodec.BufferInfo[mOutputBuffers.length];
+ mAvailableOutputBuffers.clear();
+ break;
+ case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
+ if (mOutputFormatChangedListener != null) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mOutputFormatChangedListener
+ .outputFormatChanged(MediaCodecWrapper.this,
+ mDecoder.getOutputFormat());
+
+ }
+ });
+ }
+ break;
+ default:
+ // Making sure the index is valid before adding to output buffers. We've already
+ // handled INFO_TRY_AGAIN_LATER, INFO_OUTPUT_FORMAT_CHANGED &
+ // INFO_OUTPUT_BUFFERS_CHANGED i.e all the other possible return codes but
+ // asserting index value anyways for future-proofing the code.
+ if(index >= 0) {
+ mOutputBufferInfo[index] = info;
+ mAvailableOutputBuffers.add(index);
+ } else {
+ throw new IllegalStateException("Unknown status from dequeueOutputBuffer");
+ }
+ break;
+ }
+
+ }
+ // END_INCLUDE(update_codec_state)
+
+ }
+
+ private class WriteException extends Throwable {
+ private WriteException(final String detailMessage) {
+ super(detailMessage);
+ }
+ }
+}
diff --git a/samples/browseable/BluetoothLeGatt/res/values-sw600dp/dimens.xml b/samples/browseable/BasicSyncAdapter/res/values-sw600dp/template-dimens.xml
index 22074a2bd..22074a2bd 100644
--- a/samples/browseable/BluetoothLeGatt/res/values-sw600dp/dimens.xml
+++ b/samples/browseable/BasicSyncAdapter/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/BluetoothLeGatt/res/values-sw600dp/styles.xml b/samples/browseable/BasicSyncAdapter/res/values-sw600dp/template-styles.xml
index 03d197418..03d197418 100644
--- a/samples/browseable/BluetoothLeGatt/res/values-sw600dp/styles.xml
+++ b/samples/browseable/BasicSyncAdapter/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/ImmersiveMode/res/values/dimens.xml b/samples/browseable/BasicSyncAdapter/res/values/template-dimens.xml
index 39e710b5c..39e710b5c 100644
--- a/samples/browseable/ImmersiveMode/res/values/dimens.xml
+++ b/samples/browseable/BasicSyncAdapter/res/values/template-dimens.xml
diff --git a/samples/browseable/BasicSyncAdapter/res/values/template-styles.xml b/samples/browseable/BasicSyncAdapter/res/values/template-styles.xml
new file mode 100644
index 000000000..404623e3d
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/BatchStepSensor/AndroidManifest.xml b/samples/browseable/BatchStepSensor/AndroidManifest.xml
new file mode 100644
index 000000000..2c4e4f296
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/AndroidManifest.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.batchstepsensor"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <!-- This sample requires at least Android KitKat for sensor batching support -->
+ <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19" />
+
+ <!-- Require the step counter and step detector sensors.
+ See the method BatchStepSensorFragment#isKitkatWithStepSensor() for a programmatic check if
+ support is optional and the application supports a case where these sensors are not available.
+ -->
+ <uses-feature android:name="android.hardware.sensor.stepcounter" />
+ <uses-feature android:name="android.hardware.sensor.stepdetector" />
+
+
+ <application android:allowBackup="true"
+ android:label="@string/app_name"
+ android:icon="@drawable/ic_launcher"
+ android:theme="@style/AppTheme">
+
+ <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>
+ </application>
+
+
+</manifest>
diff --git a/samples/browseable/BatchStepSensor/_index.jd b/samples/browseable/BatchStepSensor/_index.jd
new file mode 100644
index 000000000..ca7090abb
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/_index.jd
@@ -0,0 +1,21 @@
+
+
+
+page.tags="BatchStepSensor"
+sample.group=Sensors
+@jd:body
+
+<p>
+
+ This sample demonstrates the use of the two step sensors (step detector and counter) and
+ sensor batching.\n\n It shows how to register a SensorEventListener with and without
+ batching and shows how these events are received.\n\nThe Step Detector sensor fires an
+ event when a step is detected, while the step counter returns the total number of
+ steps since a listener was first registered for this sensor.
+ Both sensors only count steps while a listener is registered. This sample only covers the
+ basic case, where a listener is only registered while the app is running. Likewise,
+ batched sensors can be used in the background (when the CPU is suspended), which
+ requires manually flushing the sensor event queue before it overflows, which is not
+ covered in this sample.
+
+ </p>
diff --git a/samples/browseable/BatchStepSensor/res/drawable-hdpi/ic_action_cancel.png b/samples/browseable/BatchStepSensor/res/drawable-hdpi/ic_action_cancel.png
new file mode 100644
index 000000000..f889617e4
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable-hdpi/ic_action_cancel.png
Binary files differ
diff --git a/samples/browseable/BatchStepSensor/res/drawable-hdpi/ic_launcher.png b/samples/browseable/BatchStepSensor/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 000000000..564742cce
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BatchStepSensor/res/drawable-hdpi/tile.9.png b/samples/browseable/BatchStepSensor/res/drawable-hdpi/tile.9.png
new file mode 100644
index 000000000..135862883
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/BatchStepSensor/res/drawable-mdpi/ic_action_cancel.png b/samples/browseable/BatchStepSensor/res/drawable-mdpi/ic_action_cancel.png
new file mode 100644
index 000000000..d5a9384da
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable-mdpi/ic_action_cancel.png
Binary files differ
diff --git a/samples/browseable/BatchStepSensor/res/drawable-mdpi/ic_launcher.png b/samples/browseable/BatchStepSensor/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 000000000..08abe5759
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BatchStepSensor/res/drawable-xhdpi/card_bg.9.png b/samples/browseable/BatchStepSensor/res/drawable-xhdpi/card_bg.9.png
new file mode 100644
index 000000000..23b30c15c
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable-xhdpi/card_bg.9.png
Binary files differ
diff --git a/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_negative.png b/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_negative.png
new file mode 100644
index 000000000..1e6a64eb7
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_negative.png
Binary files differ
diff --git a/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_negative_pressed.png b/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_negative_pressed.png
new file mode 100644
index 000000000..13c105e4e
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_negative_pressed.png
Binary files differ
diff --git a/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_neutral.png b/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_neutral.png
new file mode 100644
index 000000000..f8874cdd4
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_neutral.png
Binary files differ
diff --git a/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_neutral_pressed.png b/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_neutral_pressed.png
new file mode 100644
index 000000000..a8f5e676e
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_neutral_pressed.png
Binary files differ
diff --git a/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_positive.png b/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_positive.png
new file mode 100644
index 000000000..b0a68c3a7
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_positive.png
Binary files differ
diff --git a/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_positive_pressed.png b/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_positive_pressed.png
new file mode 100644
index 000000000..528b5aaae
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_positive_pressed.png
Binary files differ
diff --git a/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..15bafae90
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BatchStepSensor/res/drawable-xxhdpi/ic_action_cancel.png b/samples/browseable/BatchStepSensor/res/drawable-xxhdpi/ic_action_cancel.png
new file mode 100644
index 000000000..331c545b8
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable-xxhdpi/ic_action_cancel.png
Binary files differ
diff --git a/samples/browseable/BatchStepSensor/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/BatchStepSensor/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..40bdd35da
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BatchStepSensor/res/drawable/card_action_bg.xml b/samples/browseable/BatchStepSensor/res/drawable/card_action_bg.xml
new file mode 100644
index 000000000..f86cf2fc5
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable/card_action_bg.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@color/card_action" android:state_pressed="true" />
+ <item android:drawable="@color/card_action_focused" android:state_focused="true" />
+ <item android:drawable="@color/card_action_item_bg" />
+</selector> \ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/drawable/card_action_bg_negative.xml b/samples/browseable/BatchStepSensor/res/drawable/card_action_bg_negative.xml
new file mode 100644
index 000000000..05d38ac02
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable/card_action_bg_negative.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@color/card_action_negative" android:state_pressed="true" />
+ <item android:drawable="@color/card_action_negative_focused" android:state_focused="true" />
+ <item android:drawable="@color/card_action_item_bg" />
+</selector> \ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/drawable/card_action_bg_positive.xml b/samples/browseable/BatchStepSensor/res/drawable/card_action_bg_positive.xml
new file mode 100644
index 000000000..4e92f24b4
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable/card_action_bg_positive.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@color/card_action_positive" android:state_pressed="true" />
+ <item android:drawable="@color/card_action_positive_focused" android:state_focused="true" />
+ <item android:drawable="@color/card_action_item_bg" />
+</selector> \ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/drawable/card_action_icon_negative.xml b/samples/browseable/BatchStepSensor/res/drawable/card_action_icon_negative.xml
new file mode 100644
index 000000000..6a797dc16
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable/card_action_icon_negative.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/ic_cardaction_negative_pressed" android:state_pressed="true" />
+ <item android:drawable="@drawable/ic_cardaction_negative" />
+</selector> \ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/drawable/card_action_icon_neutral.xml b/samples/browseable/BatchStepSensor/res/drawable/card_action_icon_neutral.xml
new file mode 100644
index 000000000..73e921474
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable/card_action_icon_neutral.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/ic_cardaction_neutral_pressed" android:state_pressed="true" />
+ <item android:drawable="@drawable/ic_cardaction_neutral" />
+</selector> \ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/drawable/card_action_icon_positive.xml b/samples/browseable/BatchStepSensor/res/drawable/card_action_icon_positive.xml
new file mode 100644
index 000000000..63f82d6c9
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable/card_action_icon_positive.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/ic_cardaction_positive_pressed" android:state_pressed="true" />
+ <item android:drawable="@drawable/ic_cardaction_positive" />
+</selector> \ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/drawable/card_action_text.xml b/samples/browseable/BatchStepSensor/res/drawable/card_action_text.xml
new file mode 100644
index 000000000..cddf5cd0d
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable/card_action_text.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true" android:color="@color/card_action_inverted" />
+ <item android:state_focused="true" android:color="@color/card_action_inverted" />
+ <item android:color="@color/card_action" />
+</selector> \ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/drawable/card_action_text_negative.xml b/samples/browseable/BatchStepSensor/res/drawable/card_action_text_negative.xml
new file mode 100644
index 000000000..90f2c05a2
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable/card_action_text_negative.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true" android:color="@color/card_action_inverted"/>
+ <item android:state_focused="true" android:color="@color/card_action_inverted"/>
+ <item android:color="@color/card_action_negative"/>
+</selector> \ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/drawable/card_action_text_positive.xml b/samples/browseable/BatchStepSensor/res/drawable/card_action_text_positive.xml
new file mode 100644
index 000000000..c3ff4024d
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable/card_action_text_positive.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true" android:color="@color/card_action_inverted"/>
+ <item android:state_focused="true" android:color="@color/card_action_inverted"/>
+ <item android:color="@color/card_action_positive"/>
+</selector> \ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/drawable/card_overlay_focused.xml b/samples/browseable/BatchStepSensor/res/drawable/card_overlay_focused.xml
new file mode 100644
index 000000000..787167d9b
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable/card_overlay_focused.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <stroke
+ android:width="5dp"
+ android:color="#aa99CC00"/>
+</shape> \ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/drawable/card_separator.xml b/samples/browseable/BatchStepSensor/res/drawable/card_separator.xml
new file mode 100644
index 000000000..6bb563010
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable/card_separator.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="line">
+ <stroke android:color="#CCC" />
+ <size android:height="1dp" />
+</shape> \ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/layout/activity_main.xml b/samples/browseable/BatchStepSensor/res/layout/activity_main.xml
new file mode 100755
index 000000000..b8a123e2b
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/layout/activity_main.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 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.
+-->
+
+
+
+<fragment
+ android:id="@+id/fragment_cardstream"
+ android:name="com.example.android.batchstepsensor.CardStreamFragment"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context=".MainActivity"
+ tools:layout="@layout/cardstream"/>
diff --git a/samples/browseable/BatchStepSensor/res/layout/card.xml b/samples/browseable/BatchStepSensor/res/layout/card.xml
new file mode 100644
index 000000000..24bffebf2
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/layout/card.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 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.
+-->
+
+
+
+<com.example.android.batchstepsensor.CardLayout
+ android:id="@+id/card_layout"
+ style="@style/Card"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <LinearLayout
+ android:id="@+id/card_actionarea"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/card_contentarea"
+ android:background="@color/card_action_bg"
+ android:orientation="vertical"
+ android:paddingBottom="@dimen/card_action_margin"
+ android:visibility="gone"
+ >
+ <include layout="@layout/card_button_seperator"/>
+ </LinearLayout>
+
+
+ <LinearLayout
+ android:id="@id/card_contentarea"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ style="@style/CardContentArea">
+
+ <TextView
+ android:id="@+id/card_title"
+ style="@style/CardTitle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+
+ <TextView
+ android:id="@+id/card_content"
+ style="@style/CardContent"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/card_title"/>
+
+ </LinearLayout>
+
+ <View
+ android:id="@+id/card_overlay"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_alignBottom="@id/card_contentarea"
+ android:layout_alignLeft="@id/card_contentarea"
+ android:layout_alignRight="@id/card_contentarea"
+ android:layout_alignTop="@id/card_contentarea"
+ android:layout_alignWithParentIfMissing="false"
+ android:visibility="invisible"/>
+
+</com.example.android.batchstepsensor.CardLayout>
diff --git a/samples/browseable/BatchStepSensor/res/layout/card_button_negative.xml b/samples/browseable/BatchStepSensor/res/layout/card_button_negative.xml
new file mode 100644
index 000000000..bf66150d1
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/layout/card_button_negative.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 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.
+-->
+
+
+
+<com.example.android.batchstepsensor.CardActionButton xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/card_button"
+ style="@style/CardActionNegative"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical" /> \ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/layout/card_button_neutral.xml b/samples/browseable/BatchStepSensor/res/layout/card_button_neutral.xml
new file mode 100644
index 000000000..7f759fc7a
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/layout/card_button_neutral.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 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.
+-->
+
+
+
+<com.example.android.batchstepsensor.CardActionButton xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/card_button"
+ style="@style/CardActionNeutral"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical" />
diff --git a/samples/browseable/BatchStepSensor/res/layout/card_button_positive.xml b/samples/browseable/BatchStepSensor/res/layout/card_button_positive.xml
new file mode 100644
index 000000000..2011f9c04
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/layout/card_button_positive.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 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.
+-->
+
+
+
+<com.example.android.batchstepsensor.CardActionButton xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/card_button"
+ style="@style/CardActionPositive"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical" />
diff --git a/samples/browseable/BatchStepSensor/res/layout/card_button_seperator.xml b/samples/browseable/BatchStepSensor/res/layout/card_button_seperator.xml
new file mode 100644
index 000000000..6731242a5
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/layout/card_button_seperator.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <ImageView
+ android:id="@+id/card_separator"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:src="@drawable/card_separator" />
+
+</merge> \ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/layout/card_progress.xml b/samples/browseable/BatchStepSensor/res/layout/card_progress.xml
new file mode 100644
index 000000000..1bf349f09
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/layout/card_progress.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ style="@style/CardProgressLayout">
+
+ <TextView
+ android:id="@+id/card_progress_text"
+ style="@style/CardProgressText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ />
+
+ <ProgressBar
+ android:id="@+id/card_progress"
+ style="@android:style/Widget.Holo.ProgressBar.Horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ />
+
+</LinearLayout> \ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/layout/cardstream.xml b/samples/browseable/BatchStepSensor/res/layout/cardstream.xml
new file mode 100644
index 000000000..463af5c55
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/layout/cardstream.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 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.
+-->
+
+
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fillViewport="true">
+
+ <com.example.android.batchstepsensor.CardStreamLinearLayout
+ style="@style/CardStream"
+ android:id="@+id/card_stream"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ </com.example.android.batchstepsensor.CardStreamLinearLayout>
+</ScrollView>
diff --git a/samples/browseable/BorderlessButtons/res/values-sw600dp/dimens.xml b/samples/browseable/BatchStepSensor/res/values-sw600dp/template-dimens.xml
index 22074a2bd..22074a2bd 100644
--- a/samples/browseable/BorderlessButtons/res/values-sw600dp/dimens.xml
+++ b/samples/browseable/BatchStepSensor/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/BorderlessButtons/res/values-sw600dp/styles.xml b/samples/browseable/BatchStepSensor/res/values-sw600dp/template-styles.xml
index 03d197418..03d197418 100644
--- a/samples/browseable/BorderlessButtons/res/values-sw600dp/styles.xml
+++ b/samples/browseable/BatchStepSensor/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/BatchStepSensor/res/values-sw720dp-land/dimens.xml b/samples/browseable/BatchStepSensor/res/values-sw720dp-land/dimens.xml
new file mode 100644
index 000000000..00059fc5c
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/values-sw720dp-land/dimens.xml
@@ -0,0 +1,5 @@
+<resources>
+ <!-- Customize dimensions originally defined in res/values/dimens.xml (such as
+ screen margins) for sw720dp devices (e.g. 10" tablets) in landscape here. -->
+ <dimen name="activity_horizontal_margin">128dp</dimen>
+</resources>
diff --git a/samples/browseable/BatchStepSensor/res/values-v11/styles.xml b/samples/browseable/BatchStepSensor/res/values-v11/styles.xml
new file mode 100644
index 000000000..3c02242ad
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/values-v11/styles.xml
@@ -0,0 +1,11 @@
+<resources>
+
+ <!--
+ Base application theme for API 11+. This theme completely replaces
+ AppBaseTheme from res/values/styles.xml on API 11+ devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Holo.Light">
+ <!-- API 11 theme customizations can go here. -->
+ </style>
+
+</resources>
diff --git a/samples/browseable/BatchStepSensor/res/values-v14/styles.xml b/samples/browseable/BatchStepSensor/res/values-v14/styles.xml
new file mode 100644
index 000000000..a91fd0372
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/values-v14/styles.xml
@@ -0,0 +1,12 @@
+<resources>
+
+ <!--
+ Base application theme for API 14+. This theme completely replaces
+ AppBaseTheme from BOTH res/values/styles.xml and
+ res/values-v11/styles.xml on API 14+ devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
+ <!-- API 14 theme customizations can go here. -->
+ </style>
+
+</resources>
diff --git a/samples/browseable/BatchStepSensor/res/values-v16/styles.xml b/samples/browseable/BatchStepSensor/res/values-v16/styles.xml
new file mode 100644
index 000000000..2b380aae0
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/values-v16/styles.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <style name="CardTitle" parent="@style/CardTitleBase">
+ <item name="android:fontFamily">sans-serif-condensed</item>
+ </style>
+
+ <style name="CardContent" parent="@style/CardContentBase">
+ <item name="android:fontFamily">sans-serif-light</item>
+ </style>
+</resources> \ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/values/attrs.xml b/samples/browseable/BatchStepSensor/res/values/attrs.xml
new file mode 100644
index 000000000..16b526006
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/values/attrs.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <declare-styleable name="CardStream">
+ <attr name="animationDuration" format="enum">
+ <enum name="slow" value="1001"/>
+ <enum name="normal" value="1002"/>
+ <enum name="fast" value="1003"/>
+ </attr>
+ <attr name="animators" format="string"/>
+ </declare-styleable>
+
+
+</resources> \ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/values/base-strings.xml b/samples/browseable/BatchStepSensor/res/values/base-strings.xml
new file mode 100644
index 000000000..341b6bc7b
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/values/base-strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+ <string name="app_name">BatchStepSensor</string>
+ <string name="intro_message">
+ <![CDATA[
+
+
+ This sample demonstrates the use of the two step sensors (step detector and counter) and
+ sensor batching.\n\n It shows how to register a SensorEventListener with and without
+ batching and shows how these events are received.\n\nThe Step Detector sensor fires an
+ event when a step is detected, while the step counter returns the total number of
+ steps since a listener was first registered for this sensor.
+ Both sensors only count steps while a listener is registered. This sample only covers the
+ basic case, where a listener is only registered while the app is running. Likewise,
+ batched sensors can be used in the background (when the CPU is suspended), which
+ requires manually flushing the sensor event queue before it overflows, which is not
+ covered in this sample.
+
+
+ ]]>
+ </string>
+</resources>
diff --git a/samples/browseable/BatchStepSensor/res/values/color.xml b/samples/browseable/BatchStepSensor/res/values/color.xml
new file mode 100644
index 000000000..98717d8d8
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/values/color.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <color name="card_action_inverted">@android:color/white</color>
+
+ <color name="card_content_textcolor">#444</color>
+
+ <color name="card_action_bg">#DDD</color>
+ <color name="card_action_item_bg">#F4F4F4</color>
+
+ <!-- Neutral Actions -->
+ <color name="card_action_focused">#FFE3F4FC</color>
+ <color name="card_action">#FF47B4EA</color>
+
+ <!-- Negative Actions -->
+ <color name="card_action_negative_focused">#FFFBCBCA</color>
+ <color name="card_action_negative">#FFF64940</color>
+
+ <!-- Positive Actions -->
+ <color name="card_action_positive_focused">#FFE4F0AF</color>
+ <color name="card_action_positive">#FFA0CC00</color>
+</resources> \ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/values/dimens.xml b/samples/browseable/BatchStepSensor/res/values/dimens.xml
new file mode 100644
index 000000000..b025f1f6e
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/values/dimens.xml
@@ -0,0 +1,14 @@
+<resources>
+
+ <dimen name="card_content_text">14sp</dimen>
+ <dimen name="card_content_title">24sp</dimen>
+
+ <dimen name="card_padding">15dp</dimen>
+ <dimen name="card_margin">10dp</dimen>
+
+ <dimen name="card_action_margin">3dp</dimen>
+ <dimen name="card_action_padding">8dp</dimen>
+
+ <dimen name="card_stream_bottom_padding">90dp</dimen>
+
+</resources>
diff --git a/samples/browseable/BatchStepSensor/res/values/ids.xml b/samples/browseable/BatchStepSensor/res/values/ids.xml
new file mode 100644
index 000000000..c5d1b78ce
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/values/ids.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <item name="card_layout" type="id"/>
+ <item name="card_actionarea" type="id"/>
+ <item name="card_contentarea" type="id"/>
+ <item name="card_title" type="id"/>
+ <item name="card_content" type="id"/>
+ <item name="card_overlay" type="id"/>
+</resources> \ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/values/strings.xml b/samples/browseable/BatchStepSensor/res/values/strings.xml
new file mode 100644
index 000000000..9c0a8add7
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/values/strings.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <string name="intro_title">Introduction</string>
+
+ <string name="batching_queue_title">Background sensor batching</string>
+ <string name="batching_queue_description">Batching allows the sensor to report sensor events at
+ a specified frequency.\n\nThe system delays calls to the SensorEventListener and deliver
+ them in intervals, based on the maximum report latency specified when the listener is
+ registered. Note that this only means that the call to onSensorChanged() is delayed, the
+ total number of calls is identical as if no batching was used. Sensors only deliver events
+ while the CPU is awake. If the CPU is asleep and a batched sensor event listener is still
+ registered, the sensor will continue to collect events until it runs out of memory and
+ overwrites old values. This use case is not covered by this sample. (The sensor event queue
+ should be flushed using a scheduled background thread.) \n\nIn this sample app data is only
+ collected while the app is running and the CPU is awake. In this case the sensor will
+ deliver events before the queue fills up.
+ </string>
+
+ <string name="explanation_description">The age of a sensor event describes the delay between
+ when it was recorded by the sensor until it was delivered to the SensorEventListener.
+ </string>
+
+ <string name="register_detector_title">Register step detector sensor</string>
+ <string name="register_detector_description">Register a listener for the STEP DETECTOR
+ sensor.\n\nThis sensor delivers an event when the user takes a step. One event is received
+ per step.
+ </string>
+
+ <string name="register_counter_title">Register step counter sensor</string>
+ <string name="register_counter_description">Register a listener for the STEP COUNTER
+ sensor.\n\nThis sensor triggers events when a step is detected, but applies algorithms to
+ filter out false positives. Events from this sensor have higher latency than the step
+ detector and contain the total number of steps taken since the sensor was first registered.
+ </string>
+
+ <string name="register_0">No batching (delay=0)</string>
+ <string name="register_5">5s batching (delay=5000ms)</string>
+ <string name="register_10">10s batching (delay=10000ms)</string>
+
+ <string name="counting_title">Total Steps: %1$d</string>
+ <string name="sensor_counter">Step Counter</string>
+ <string name="sensor_detector">Step Detector</string>
+ <string name="counting_description">Sensor: %1$s\nMax sensor event delay: %2$,d \u00B5s\nAge of
+ events in s:\n%3$s
+ </string>
+
+ <string name="error_title">Error</string>
+ <string name="error_nosensor">This sample requires at least Android KitKat (4.4) and a device
+ with the step sensor.\n\nThis device does not appear to meet these requirements, as an
+ alternative you may want to consider using the gyro sensor and implement your own step
+ recognition as a fallback.
+ </string>
+ <string name="warning_nobatching">The listener has been registered, but batch mode could not be
+ enabled.\n\nIt is likely that it is not supported by this device.\n\nSensor events will be
+ delivered in continuous mode.
+ </string>
+
+ <string name="action_notagain">Do not show again</string>
+</resources> \ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/values/styles.xml b/samples/browseable/BatchStepSensor/res/values/styles.xml
new file mode 100644
index 000000000..23e8181ba
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/values/styles.xml
@@ -0,0 +1,92 @@
+<resources>
+
+ <!-- Card Stream -->
+ <style name="CardStream">
+ <item name="android:paddingBottom">@dimen/card_stream_bottom_padding</item>
+ <item name="android:divider">@null</item>
+ <item name="android:orientation">vertical</item>
+ </style>
+
+ <!-- Main card -->
+ <style name="Card">
+ <item name="android:background">@drawable/card_bg</item>
+ <item name="android:layout_margin">@dimen/card_margin</item>
+ </style>
+
+ <style name="CardContentArea">
+ <item name="android:paddingBottom">@dimen/card_padding</item>
+ </style>
+
+ <style name="CardActionArea">
+ <item name="android:background">@color/card_action_bg</item>
+ <item name="android:orientation">vertical</item>
+ <item name="android:paddingBottom">@dimen/card_action_margin</item>
+ </style>
+
+ <style name="CardElement">
+ <item name="android:paddingLeft">@dimen/card_padding</item>
+ <item name="android:paddingRight">@dimen/card_padding</item>
+ </style>
+
+ <!-- Content of main card -->
+ <style name="CardTitleBase" parent="@style/CardElement">
+ <item name="android:paddingTop">@dimen/card_padding</item>
+ <item name="android:textSize">@dimen/card_content_title</item>
+ </style>
+
+ <style name="CardTitle" parent="@style/CardTitleBase">
+ </style>
+
+ <style name="CardContentBase" parent="@style/CardElement">
+ <item name="android:paddingTop">@dimen/card_padding</item>
+ <item name="android:textSize">@dimen/card_content_text</item>
+ <item name="android:textColor">@color/card_content_textcolor</item>
+ </style>
+
+ <style name="CardContent" parent="@style/CardContentBase">
+ </style>
+
+ <!-- Action Area Items -->
+ <style name="CardAction">
+ <item name="android:textSize">17sp</item>
+ <item name="android:layout_marginTop">@dimen/card_action_margin</item>
+ <item name="android:layout_marginLeft">@dimen/card_action_margin</item>
+ <item name="android:layout_marginRight">@dimen/card_action_margin</item>
+ <item name="android:paddingLeft">@dimen/card_action_padding</item>
+ <item name="android:drawablePadding">@dimen/card_action_padding</item>
+ </style>
+
+ <style name="CardActionNeutral" parent="@style/CardAction">
+ <item name="android:background">@drawable/card_action_bg</item>
+ <item name="android:drawableStart">@drawable/card_action_icon_neutral</item>
+ <item name="android:textColor">@drawable/card_action_text</item>
+ </style>
+
+ <style name="CardActionNegative" parent="@style/CardAction">
+ <item name="android:background">@drawable/card_action_bg_negative</item>
+ <item name="android:drawableStart">@drawable/card_action_icon_negative</item>
+ <item name="android:textColor">@drawable/card_action_text_negative</item>
+ </style>
+
+ <style name="CardActionPositive" parent="@style/CardAction">
+ <item name="android:background">@drawable/card_action_bg_positive</item>
+ <item name="android:drawableStart">@drawable/card_action_icon_positive</item>
+ <item name="android:textColor">@drawable/card_action_text_positive</item>
+ </style>
+
+ <!-- Card Action Progress -->
+ <style name="CardProgressLayout" parent="@style/CardAction">
+ <item name="android:layout_marginLeft">@dimen/card_action_margin</item>
+ <item name="android:layout_marginRight">@dimen/card_action_margin</item>
+ <item name="android:paddingLeft">@dimen/card_action_padding</item>
+ <item name="android:paddingRight">@dimen/card_action_padding</item>
+ <item name="android:background">#EEE</item>
+ </style>
+
+ <style name="CardProgressText" parent="@style/CardAction">
+ <item name="android:textColor">#77000000</item>
+ <item name="android:textSize">12sp</item>
+ <item name="android:paddingLeft">0dp</item>
+ </style>
+
+</resources> \ No newline at end of file
diff --git a/samples/browseable/NetworkConnect/res/values/dimens.xml b/samples/browseable/BatchStepSensor/res/values/template-dimens.xml
index 39e710b5c..39e710b5c 100644
--- a/samples/browseable/NetworkConnect/res/values/dimens.xml
+++ b/samples/browseable/BatchStepSensor/res/values/template-dimens.xml
diff --git a/samples/browseable/BatchStepSensor/res/values/template-styles.xml b/samples/browseable/BatchStepSensor/res/values/template-styles.xml
new file mode 100644
index 000000000..404623e3d
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/BatchStepSensorFragment.java b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/BatchStepSensorFragment.java
new file mode 100644
index 000000000..aab0fc388
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/BatchStepSensorFragment.java
@@ -0,0 +1,588 @@
+/*
+* Copyright 2014 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.example.android.batchstepsensor;
+
+import android.app.Activity;
+import android.content.pm.PackageManager;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+
+import com.example.android.common.logger.Log;
+
+public class BatchStepSensorFragment extends Fragment implements OnCardClickListener {
+
+ public static final String TAG = "StepSensorSample";
+ // Cards
+ private CardStreamFragment mCards = null;
+
+ // Card tags
+ public static final String CARD_INTRO = "intro";
+ public static final String CARD_REGISTER_DETECTOR = "register_detector";
+ public static final String CARD_REGISTER_COUNTER = "register_counter";
+ public static final String CARD_BATCHING_DESCRIPTION = "register_batching_description";
+ public static final String CARD_COUNTING = "counting";
+ public static final String CARD_EXPLANATION = "explanation";
+ public static final String CARD_NOBATCHSUPPORT = "error";
+
+ // Actions from REGISTER cards
+ public static final int ACTION_REGISTER_DETECT_NOBATCHING = 10;
+ public static final int ACTION_REGISTER_DETECT_BATCHING_5s = 11;
+ public static final int ACTION_REGISTER_DETECT_BATCHING_10s = 12;
+ public static final int ACTION_REGISTER_COUNT_NOBATCHING = 21;
+ public static final int ACTION_REGISTER_COUNT_BATCHING_5s = 22;
+ public static final int ACTION_REGISTER_COUNT_BATCHING_10s = 23;
+ // Action from COUNTING card
+ public static final int ACTION_UNREGISTER = 1;
+ // Actions from description cards
+ private static final int ACTION_BATCHING_DESCRIPTION_DISMISS = 2;
+ private static final int ACTION_EXPLANATION_DISMISS = 3;
+
+ // State of application, used to register for sensors when app is restored
+ public static final int STATE_OTHER = 0;
+ public static final int STATE_COUNTER = 1;
+ public static final int STATE_DETECTOR = 2;
+
+ // Bundle tags used to store data when restoring application state
+ private static final String BUNDLE_STATE = "state";
+ private static final String BUNDLE_LATENCY = "latency";
+ private static final String BUNDLE_STEPS = "steps";
+
+ // max batch latency is specified in microseconds
+ private static final int BATCH_LATENCY_0 = 0; // no batching
+ private static final int BATCH_LATENCY_10s = 10000000;
+ private static final int BATCH_LATENCY_5s = 5000000;
+
+ /*
+ For illustration we keep track of the last few events and show their delay from when the
+ event occurred until it was received by the event listener.
+ These variables keep track of the list of timestamps and the number of events.
+ */
+ // Number of events to keep in queue and display on card
+ private static final int EVENT_QUEUE_LENGTH = 10;
+ // List of timestamps when sensor events occurred
+ private float[] mEventDelays = new float[EVENT_QUEUE_LENGTH];
+
+ // number of events in event list
+ private int mEventLength = 0;
+ // pointer to next entry in sensor event list
+ private int mEventData = 0;
+
+ // Steps counted in current session
+ private int mSteps = 0;
+ // Value of the step counter sensor when the listener was registered.
+ // (Total steps are calculated from this value.)
+ private int mCounterSteps = 0;
+ // Steps counted by the step counter previously. Used to keep counter consistent across rotation
+ // changes
+ private int mPreviousCounterSteps = 0;
+ // State of the app (STATE_OTHER, STATE_COUNTER or STATE_DETECTOR)
+ private int mState = STATE_OTHER;
+ // When a listener is registered, the batch sensor delay in microseconds
+ private int mMaxDelay = 0;
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ CardStreamFragment stream = getCardStream();
+ if (stream.getVisibleCardCount() < 1) {
+ // No cards are visible, started for the first time
+ // Prepare all cards and show the intro card.
+ initialiseCards();
+ showIntroCard();
+ // Show the registration card if the hardware is supported, show an error otherwise
+ if (isKitkatWithStepSensor()) {
+ showRegisterCard();
+ } else {
+ showErrorCard();
+ }
+ }
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ // BEGIN_INCLUDE(onpause)
+ // Unregister the listener when the application is paused
+ unregisterListeners();
+ // END_INCLUDE(onpause)
+ }
+
+ /**
+ * Returns true if this device is supported. It needs to be running Android KitKat (4.4) or
+ * higher and has a step counter and step detector sensor.
+ * This check is useful when an app provides an alternative implementation or different
+ * functionality if the step sensors are not available or this code runs on a platform version
+ * below Android KitKat. If this functionality is required, then the minSDK parameter should
+ * be specified appropriately in the AndroidManifest.
+ *
+ * @return True iff the device can run this sample
+ */
+ private boolean isKitkatWithStepSensor() {
+ // BEGIN_INCLUDE(iskitkatsensor)
+ // Require at least Android KitKat
+ int currentApiVersion = android.os.Build.VERSION.SDK_INT;
+ // Check that the device supports the step counter and detector sensors
+ PackageManager packageManager = getActivity().getPackageManager();
+ return currentApiVersion >= android.os.Build.VERSION_CODES.KITKAT
+ && packageManager.hasSystemFeature(PackageManager.FEATURE_SENSOR_STEP_COUNTER)
+ && packageManager.hasSystemFeature(PackageManager.FEATURE_SENSOR_STEP_DETECTOR);
+ // END_INCLUDE(iskitkatsensor)
+ }
+
+ /**
+ * Handles a click on a card action.
+ * Registers a SensorEventListener (see {@link #registerEventListener(int, int)}) with the
+ * selected delay, dismisses cards and unregisters the listener
+ * (see {@link #unregisterListeners()}).
+ * Actions are defined when a card is created.
+ *
+ * @param cardActionId
+ * @param cardTag
+ */
+ @Override
+ public void onCardClick(int cardActionId, String cardTag) {
+
+ switch (cardActionId) {
+ // BEGIN_INCLUDE(onclick)
+ // Register Step Counter card
+ case ACTION_REGISTER_COUNT_NOBATCHING:
+ registerEventListener(BATCH_LATENCY_0, Sensor.TYPE_STEP_COUNTER);
+ break;
+ case ACTION_REGISTER_COUNT_BATCHING_5s:
+ registerEventListener(BATCH_LATENCY_5s, Sensor.TYPE_STEP_COUNTER);
+ break;
+ case ACTION_REGISTER_COUNT_BATCHING_10s:
+ registerEventListener(BATCH_LATENCY_10s, Sensor.TYPE_STEP_COUNTER);
+ break;
+
+ // Register Step Detector card
+ case ACTION_REGISTER_DETECT_NOBATCHING:
+ registerEventListener(BATCH_LATENCY_0, Sensor.TYPE_STEP_DETECTOR);
+ break;
+ case ACTION_REGISTER_DETECT_BATCHING_5s:
+ registerEventListener(BATCH_LATENCY_5s, Sensor.TYPE_STEP_DETECTOR);
+ break;
+ case ACTION_REGISTER_DETECT_BATCHING_10s:
+ registerEventListener(BATCH_LATENCY_10s, Sensor.TYPE_STEP_DETECTOR);
+ break;
+
+ // Unregister card
+ case ACTION_UNREGISTER:
+ showRegisterCard();
+ unregisterListeners();
+ // reset the application state when explicitly unregistered
+ mState = STATE_OTHER;
+ break;
+ // END_INCLUDE(onclick)
+ // Explanation cards
+ case ACTION_BATCHING_DESCRIPTION_DISMISS:
+ // permanently remove the batch description card, it will not be shown again
+ getCardStream().removeCard(CARD_BATCHING_DESCRIPTION);
+ break;
+ case ACTION_EXPLANATION_DISMISS:
+ // permanently remove the explanation card, it will not be shown again
+ getCardStream().removeCard(CARD_EXPLANATION);
+ }
+
+ // For register cards, display the counting card
+ if (cardTag.equals(CARD_REGISTER_COUNTER) || cardTag.equals(CARD_REGISTER_DETECTOR)) {
+ showCountingCards();
+ }
+ }
+
+ /**
+ * Register a {@link android.hardware.SensorEventListener} for the sensor and max batch delay.
+ * The maximum batch delay specifies the maximum duration in microseconds for which subsequent
+ * sensor events can be temporarily stored by the sensor before they are delivered to the
+ * registered SensorEventListener. A larger delay allows the system to handle sensor events more
+ * efficiently, allowing the system to switch to a lower power state while the sensor is
+ * capturing events. Once the max delay is reached, all stored events are delivered to the
+ * registered listener. Note that this value only specifies the maximum delay, the listener may
+ * receive events quicker. A delay of 0 disables batch mode and registers the listener in
+ * continuous mode.
+ * The optimium batch delay depends on the application. For example, a delay of 5 seconds or
+ * higher may be appropriate for an application that does not update the UI in real time.
+ *
+ * @param maxdelay
+ * @param sensorType
+ */
+ private void registerEventListener(int maxdelay, int sensorType) {
+ // BEGIN_INCLUDE(register)
+
+ // Keep track of state so that the correct sensor type and batch delay can be set up when
+ // the app is restored (for example on screen rotation).
+ mMaxDelay = maxdelay;
+ if (sensorType == Sensor.TYPE_STEP_COUNTER) {
+ mState = STATE_COUNTER;
+ /*
+ Reset the initial step counter value, the first event received by the event listener is
+ stored in mCounterSteps and used to calculate the total number of steps taken.
+ */
+ mCounterSteps = 0;
+ Log.i(TAG, "Event listener for step counter sensor registered with a max delay of "
+ + mMaxDelay);
+ } else {
+ mState = STATE_DETECTOR;
+ Log.i(TAG, "Event listener for step detector sensor registered with a max delay of "
+ + mMaxDelay);
+ }
+
+ // Get the default sensor for the sensor type from the SenorManager
+ SensorManager sensorManager =
+ (SensorManager) getActivity().getSystemService(Activity.SENSOR_SERVICE);
+ // sensorType is either Sensor.TYPE_STEP_COUNTER or Sensor.TYPE_STEP_DETECTOR
+ Sensor sensor = sensorManager.getDefaultSensor(sensorType);
+
+ // Register the listener for this sensor in batch mode.
+ // If the max delay is 0, events will be delivered in continuous mode without batching.
+ final boolean batchMode = sensorManager.registerListener(
+ mListener, sensor, SensorManager.SENSOR_DELAY_NORMAL, maxdelay);
+
+ if (!batchMode) {
+ // Batch mode could not be enabled, show a warning message and switch to continuous mode
+ getCardStream().getCard(CARD_NOBATCHSUPPORT)
+ .setDescription(getString(R.string.warning_nobatching));
+ getCardStream().showCard(CARD_NOBATCHSUPPORT);
+ Log.w(TAG, "Could not register sensor listener in batch mode, " +
+ "falling back to continuous mode.");
+ }
+
+ if (maxdelay > 0 && batchMode) {
+ // Batch mode was enabled successfully, show a description card
+ getCardStream().showCard(CARD_BATCHING_DESCRIPTION);
+ }
+
+ // Show the explanation card
+ getCardStream().showCard(CARD_EXPLANATION);
+
+ // END_INCLUDE(register)
+
+ }
+
+ /**
+ * Unregisters the sensor listener if it is registered.
+ */
+ private void unregisterListeners() {
+ // BEGIN_INCLUDE(unregister)
+ SensorManager sensorManager =
+ (SensorManager) getActivity().getSystemService(Activity.SENSOR_SERVICE);
+ sensorManager.unregisterListener(mListener);
+ Log.i(TAG, "Sensor listener unregistered.");
+
+ // END_INCLUDE(unregister)
+ }
+
+ /**
+ * Resets the step counter by clearing all counting variables and lists.
+ */
+ private void resetCounter() {
+ // BEGIN_INCLUDE(reset)
+ mSteps = 0;
+ mCounterSteps = 0;
+ mEventLength = 0;
+ mEventDelays = new float[EVENT_QUEUE_LENGTH];
+ mPreviousCounterSteps = 0;
+ // END_INCLUDE(reset)
+ }
+
+
+ /**
+ * Listener that handles step sensor events for step detector and step counter sensors.
+ */
+ private final SensorEventListener mListener = new SensorEventListener() {
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ // BEGIN_INCLUDE(sensorevent)
+ // store the delay of this event
+ recordDelay(event);
+ final String delayString = getDelayString();
+
+ if (event.sensor.getType() == Sensor.TYPE_STEP_DETECTOR) {
+ // A step detector event is received for each step.
+ // This means we need to count steps ourselves
+
+ mSteps += event.values.length;
+
+ // Update the card with the latest step count
+ getCardStream().getCard(CARD_COUNTING)
+ .setTitle(getString(R.string.counting_title, mSteps))
+ .setDescription(getString(R.string.counting_description,
+ getString(R.string.sensor_detector), mMaxDelay, delayString));
+
+ Log.i(TAG,
+ "New step detected by STEP_DETECTOR sensor. Total step count: " + mSteps);
+
+ } else if (event.sensor.getType() == Sensor.TYPE_STEP_COUNTER) {
+
+ /*
+ A step counter event contains the total number of steps since the listener
+ was first registered. We need to keep track of this initial value to calculate the
+ number of steps taken, as the first value a listener receives is undefined.
+ */
+ if (mCounterSteps < 1) {
+ // initial value
+ mCounterSteps = (int) event.values[0];
+ }
+
+ // Calculate steps taken based on first counter value received.
+ mSteps = (int) event.values[0] - mCounterSteps;
+
+ // Add the number of steps previously taken, otherwise the counter would start at 0.
+ // This is needed to keep the counter consistent across rotation changes.
+ mSteps = mSteps + mPreviousCounterSteps;
+
+ // Update the card with the latest step count
+ getCardStream().getCard(CARD_COUNTING)
+ .setTitle(getString(R.string.counting_title, mSteps))
+ .setDescription(getString(R.string.counting_description,
+ getString(R.string.sensor_counter), mMaxDelay, delayString));
+ Log.i(TAG, "New step detected by STEP_COUNTER sensor. Total step count: " + mSteps);
+ // END_INCLUDE(sensorevent)
+ }
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+
+ }
+ };
+
+ /**
+ * Records the delay for the event.
+ *
+ * @param event
+ */
+ private void recordDelay(SensorEvent event) {
+ // Calculate the delay from when event was recorded until it was received here in ms
+ // Event timestamp is recorded in us accuracy, but ms accuracy is sufficient here
+ mEventDelays[mEventData] = System.currentTimeMillis() - (event.timestamp / 1000000L);
+
+ // Increment length counter
+ mEventLength = Math.min(EVENT_QUEUE_LENGTH, mEventLength + 1);
+ // Move pointer to the next (oldest) location
+ mEventData = (mEventData + 1) % EVENT_QUEUE_LENGTH;
+ }
+
+ private final StringBuffer mDelayStringBuffer = new StringBuffer();
+
+ /**
+ * Returns a string describing the sensor delays recorded in
+ * {@link #recordDelay(android.hardware.SensorEvent)}.
+ *
+ * @return
+ */
+ private String getDelayString() {
+ // Empty the StringBuffer
+ mDelayStringBuffer.setLength(0);
+
+ // Loop over all recorded delays and append them to the buffer as a decimal
+ for (int i = 0; i < mEventLength; i++) {
+ if (i > 0) {
+ mDelayStringBuffer.append(", ");
+ }
+ final int index = (mEventData + i) % EVENT_QUEUE_LENGTH;
+ final float delay = mEventDelays[index] / 1000f; // convert delay from ms into s
+ mDelayStringBuffer.append(String.format("%1.1f", delay));
+ }
+
+ return mDelayStringBuffer.toString();
+ }
+
+ /**
+ * Records the state of the application into the {@link android.os.Bundle}.
+ *
+ * @param outState
+ */
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ // BEGIN_INCLUDE(saveinstance)
+ super.onSaveInstanceState(outState);
+ // Store all variables required to restore the state of the application
+ outState.putInt(BUNDLE_LATENCY, mMaxDelay);
+ outState.putInt(BUNDLE_STATE, mState);
+ outState.putInt(BUNDLE_STEPS, mSteps);
+ // END_INCLUDE(saveinstance)
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ // BEGIN_INCLUDE(restore)
+ // Fragment is being restored, reinitialise its state with data from the bundle
+ if (savedInstanceState != null) {
+ resetCounter();
+ mSteps = savedInstanceState.getInt(BUNDLE_STEPS);
+ mState = savedInstanceState.getInt(BUNDLE_STATE);
+ mMaxDelay = savedInstanceState.getInt(BUNDLE_LATENCY);
+
+ // Register listeners again if in detector or counter states with restored delay
+ if (mState == STATE_DETECTOR) {
+ registerEventListener(mMaxDelay, Sensor.TYPE_STEP_DETECTOR);
+ } else if (mState == STATE_COUNTER) {
+ // store the previous number of steps to keep step counter count consistent
+ mPreviousCounterSteps = mSteps;
+ registerEventListener(mMaxDelay, Sensor.TYPE_STEP_COUNTER);
+ }
+ }
+ // END_INCLUDE(restore)
+ }
+
+ /**
+ * Hides the registration cards, reset the counter and show the step counting card.
+ */
+ private void showCountingCards() {
+ // Hide the registration cards
+ getCardStream().hideCard(CARD_REGISTER_DETECTOR);
+ getCardStream().hideCard(CARD_REGISTER_COUNTER);
+
+ // Show the explanation card if it has not been dismissed
+ getCardStream().showCard(CARD_EXPLANATION);
+
+ // Reset the step counter, then show the step counting card
+ resetCounter();
+
+ // Set the inital text for the step counting card before a step is recorded
+ String sensor = "-";
+ if (mState == STATE_COUNTER) {
+ sensor = getString(R.string.sensor_counter);
+ } else if (mState == STATE_DETECTOR) {
+ sensor = getString(R.string.sensor_detector);
+ }
+ // Set initial text
+ getCardStream().getCard(CARD_COUNTING)
+ .setTitle(getString(R.string.counting_title, 0))
+ .setDescription(getString(R.string.counting_description, sensor, mMaxDelay, "-"));
+
+ // Show the counting card and make it undismissable
+ getCardStream().showCard(CARD_COUNTING, false);
+
+ }
+
+ /**
+ * Show the introduction card
+ */
+ private void showIntroCard() {
+ Card c = new Card.Builder(this, CARD_INTRO)
+ .setTitle(getString(R.string.intro_title))
+ .setDescription(getString(R.string.intro_message))
+ .build(getActivity());
+ getCardStream().addCard(c, true);
+ }
+
+ /**
+ * Show two registration cards, one for the step detector and counter sensors.
+ */
+ private void showRegisterCard() {
+ // Hide the counting and explanation cards
+ getCardStream().hideCard(CARD_BATCHING_DESCRIPTION);
+ getCardStream().hideCard(CARD_EXPLANATION);
+ getCardStream().hideCard(CARD_COUNTING);
+
+ // Show two undismissable registration cards, one for each step sensor
+ getCardStream().showCard(CARD_REGISTER_DETECTOR, false);
+ getCardStream().showCard(CARD_REGISTER_COUNTER, false);
+ }
+
+ /**
+ * Show the error card.
+ */
+ private void showErrorCard() {
+ getCardStream().showCard(CARD_NOBATCHSUPPORT, false);
+ }
+
+ /**
+ * Initialise Cards.
+ */
+ private void initialiseCards() {
+ // Step counting
+ Card c = new Card.Builder(this, CARD_COUNTING)
+ .setTitle("Steps")
+ .setDescription("")
+ .addAction("Unregister Listener", ACTION_UNREGISTER, Card.ACTION_NEGATIVE)
+ .build(getActivity());
+ getCardStream().addCard(c);
+
+ // Register step detector listener
+ c = new Card.Builder(this, CARD_REGISTER_DETECTOR)
+ .setTitle(getString(R.string.register_detector_title))
+ .setDescription(getString(R.string.register_detector_description))
+ .addAction(getString(R.string.register_0),
+ ACTION_REGISTER_DETECT_NOBATCHING, Card.ACTION_NEUTRAL)
+ .addAction(getString(R.string.register_5),
+ ACTION_REGISTER_DETECT_BATCHING_5s, Card.ACTION_NEUTRAL)
+ .addAction(getString(R.string.register_10),
+ ACTION_REGISTER_DETECT_BATCHING_10s, Card.ACTION_NEUTRAL)
+ .build(getActivity());
+ getCardStream().addCard(c);
+
+ // Register step counter listener
+ c = new Card.Builder(this, CARD_REGISTER_COUNTER)
+ .setTitle(getString(R.string.register_counter_title))
+ .setDescription(getString(R.string.register_counter_description))
+ .addAction(getString(R.string.register_0),
+ ACTION_REGISTER_COUNT_NOBATCHING, Card.ACTION_NEUTRAL)
+ .addAction(getString(R.string.register_5),
+ ACTION_REGISTER_COUNT_BATCHING_5s, Card.ACTION_NEUTRAL)
+ .addAction(getString(R.string.register_10),
+ ACTION_REGISTER_COUNT_BATCHING_10s, Card.ACTION_NEUTRAL)
+ .build(getActivity());
+ getCardStream().addCard(c);
+
+
+ // Batching description
+ c = new Card.Builder(this, CARD_BATCHING_DESCRIPTION)
+ .setTitle(getString(R.string.batching_queue_title))
+ .setDescription(getString(R.string.batching_queue_description))
+ .addAction(getString(R.string.action_notagain),
+ ACTION_BATCHING_DESCRIPTION_DISMISS, Card.ACTION_POSITIVE)
+ .build(getActivity());
+ getCardStream().addCard(c);
+
+ // Explanation
+ c = new Card.Builder(this, CARD_EXPLANATION)
+ .setDescription(getString(R.string.explanation_description))
+ .addAction(getString(R.string.action_notagain),
+ ACTION_EXPLANATION_DISMISS, Card.ACTION_POSITIVE)
+ .build(getActivity());
+ getCardStream().addCard(c);
+
+ // Error
+ c = new Card.Builder(this, CARD_NOBATCHSUPPORT)
+ .setTitle(getString(R.string.error_title))
+ .setDescription(getString(R.string.error_nosensor))
+ .build(getActivity());
+ getCardStream().addCard(c);
+ }
+
+ /**
+ * Returns the cached CardStreamFragment used to show cards.
+ *
+ * @return
+ */
+ private CardStreamFragment getCardStream() {
+ if (mCards == null) {
+ mCards = ((CardStream) getActivity()).getCardStream();
+ }
+ return mCards;
+ }
+
+}
diff --git a/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/Card.java b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/Card.java
new file mode 100644
index 000000000..fb885c7d6
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/Card.java
@@ -0,0 +1,750 @@
+/*
+* Copyright 2013 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.example.android.batchstepsensor;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.app.Activity;
+import android.graphics.Color;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+
+/**
+ * A Card contains a description and has a visual state. Optionally a card also contains a title,
+ * progress indicator and zero or more actions. It is constructed through the {@link Builder}.
+ */
+public class Card {
+
+ public static final int ACTION_POSITIVE = 1;
+ public static final int ACTION_NEGATIVE = 2;
+ public static final int ACTION_NEUTRAL = 3;
+
+ public static final int PROGRESS_TYPE_NO_PROGRESS = 0;
+ public static final int PROGRESS_TYPE_NORMAL = 1;
+ public static final int PROGRESS_TYPE_INDETERMINATE = 2;
+ public static final int PROGRESS_TYPE_LABEL = 3;
+
+ private OnCardClickListener mClickListener;
+
+
+ // The card model contains a reference to its desired layout (for extensibility), title,
+ // description, zero to many action buttons, and zero or 1 progress indicators.
+ private int mLayoutId = R.layout.card;
+
+ /**
+ * Tag that uniquely identifies this card.
+ */
+ private String mTag = null;
+
+ private String mTitle = null;
+ private String mDescription = null;
+
+ private View mCardView = null;
+ private View mOverlayView = null;
+ private TextView mTitleView = null;
+ private TextView mDescView = null;
+ private View mActionAreaView = null;
+
+ private Animator mOngoingAnimator = null;
+
+ /**
+ * Visual state, either {@link #CARD_STATE_NORMAL}, {@link #CARD_STATE_FOCUSED} or
+ * {@link #CARD_STATE_INACTIVE}.
+ */
+ private int mCardState = CARD_STATE_NORMAL;
+ public static final int CARD_STATE_NORMAL = 1;
+ public static final int CARD_STATE_FOCUSED = 2;
+ public static final int CARD_STATE_INACTIVE = 3;
+
+ /**
+ * Represent actions that can be taken from the card. Stylistically the developer can
+ * designate the action as positive, negative (ok/cancel, for instance), or neutral.
+ * This "type" can be used as a UI hint.
+ * @see com.example.android.sensors.batchstepsensor.Card.CardAction
+ */
+ private ArrayList<CardAction> mCardActions = new ArrayList<CardAction>();
+
+ /**
+ * Some cards will have a sense of "progress" which should be associated with, but separated
+ * from its "parent" card. To push for simplicity in samples, Cards are designed to have
+ * a maximum of one progress indicator per Card.
+ */
+ private CardProgress mCardProgress = null;
+
+ public Card() {
+ }
+
+ public String getTag() {
+ return mTag;
+ }
+
+ public View getView() {
+ return mCardView;
+ }
+
+
+ public Card setDescription(String desc) {
+ if (mDescView != null) {
+ mDescription = desc;
+ mDescView.setText(desc);
+ }
+ return this;
+ }
+
+ public Card setTitle(String title) {
+ if (mTitleView != null) {
+ mTitle = title;
+ mTitleView.setText(title);
+ }
+ return this;
+ }
+
+
+ /**
+ * Return the UI state, either {@link #CARD_STATE_NORMAL}, {@link #CARD_STATE_FOCUSED}
+ * or {@link #CARD_STATE_INACTIVE}.
+ */
+ public int getState() {
+ return mCardState;
+ }
+
+ /**
+ * Set the UI state. The parameter describes the state and must be either
+ * {@link #CARD_STATE_NORMAL}, {@link #CARD_STATE_FOCUSED} or {@link #CARD_STATE_INACTIVE}.
+ * Note: This method must be called from the UI Thread.
+ * @param state
+ * @return The card itself, allows for chaining of calls
+ */
+ public Card setState(int state) {
+ mCardState = state;
+ if (null != mOverlayView) {
+ if (null != mOngoingAnimator) {
+ mOngoingAnimator.end();
+ mOngoingAnimator = null;
+ }
+ switch (state) {
+ case CARD_STATE_NORMAL: {
+ mOverlayView.setVisibility(View.GONE);
+ mOverlayView.setAlpha(1.f);
+ break;
+ }
+ case CARD_STATE_FOCUSED: {
+ mOverlayView.setVisibility(View.VISIBLE);
+ mOverlayView.setBackgroundResource(R.drawable.card_overlay_focused);
+ ObjectAnimator animator = ObjectAnimator.ofFloat(mOverlayView, "alpha", 0.f);
+ animator.setRepeatMode(ObjectAnimator.REVERSE);
+ animator.setRepeatCount(ObjectAnimator.INFINITE);
+ animator.setDuration(1000);
+ animator.start();
+ mOngoingAnimator = animator;
+ break;
+ }
+ case CARD_STATE_INACTIVE: {
+ mOverlayView.setVisibility(View.VISIBLE);
+ mOverlayView.setAlpha(1.f);
+ mOverlayView.setBackgroundColor(Color.argb(0xaa, 0xcc, 0xcc, 0xcc));
+ break;
+ }
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Set the type of progress indicator.
+ * The progress type can only be changed if the Card was initially build with a progress
+ * indicator.
+ * See {@link Builder#setProgressType(int)}.
+ * Must be a value of either {@link #PROGRESS_TYPE_NORMAL},
+ * {@link #PROGRESS_TYPE_INDETERMINATE}, {@link #PROGRESS_TYPE_LABEL} or
+ * {@link #PROGRESS_TYPE_NO_PROGRESS}.
+ * @param progressType
+ * @return The card itself, allows for chaining of calls
+ */
+ public Card setProgressType(int progressType) {
+ if (mCardProgress == null) {
+ mCardProgress = new CardProgress();
+ }
+ mCardProgress.setProgressType(progressType);
+ return this;
+ }
+
+ /**
+ * Return the progress indicator type. A value of either {@link #PROGRESS_TYPE_NORMAL},
+ * {@link #PROGRESS_TYPE_INDETERMINATE}, {@link #PROGRESS_TYPE_LABEL}. Otherwise if no progress
+ * indicator is enabled, {@link #PROGRESS_TYPE_NO_PROGRESS} is returned.
+ * @return
+ */
+ public int getProgressType() {
+ if (mCardProgress == null) {
+ return PROGRESS_TYPE_NO_PROGRESS;
+ }
+ return mCardProgress.progressType;
+ }
+
+ /**
+ * Set the progress to the specified value. Only applicable if the card has a
+ * {@link #PROGRESS_TYPE_NORMAL} progress type.
+ * @param progress
+ * @return
+ * @see #setMaxProgress(int)
+ */
+ public Card setProgress(int progress) {
+ if (mCardProgress != null) {
+ mCardProgress.setProgress(progress);
+ }
+ return this;
+ }
+
+ /**
+ * Set the range of the progress to 0...max. Only applicable if the card has a
+ * {@link #PROGRESS_TYPE_NORMAL} progress type.
+ * @return
+ */
+ public Card setMaxProgress(int max){
+ if (mCardProgress != null) {
+ mCardProgress.setMax(max);
+ }
+ return this;
+ }
+
+ /**
+ * Set the label text for the progress if the card has a progress type of
+ * {@link #PROGRESS_TYPE_NORMAL}, {@link #PROGRESS_TYPE_INDETERMINATE} or
+ * {@link #PROGRESS_TYPE_LABEL}
+ * @param text
+ * @return
+ */
+ public Card setProgressLabel(String text) {
+ if (mCardProgress != null) {
+ mCardProgress.setProgressLabel(text);
+ }
+ return this;
+ }
+
+ /**
+ * Toggle the visibility of the progress section of the card. Only applicable if
+ * the card has a progress type of
+ * {@link #PROGRESS_TYPE_NORMAL}, {@link #PROGRESS_TYPE_INDETERMINATE} or
+ * {@link #PROGRESS_TYPE_LABEL}.
+ * @param isVisible
+ * @return
+ */
+ public Card setProgressVisibility(boolean isVisible) {
+ if (mCardProgress.progressView == null) {
+ return this; // Card does not have progress
+ }
+ mCardProgress.progressView.setVisibility(isVisible ? View.VISIBLE : View.GONE);
+
+ return this;
+ }
+
+ /**
+ * Adds an action to this card during build time.
+ *
+ * @param label
+ * @param id
+ * @param type
+ */
+ private void addAction(String label, int id, int type) {
+ CardAction cardAction = new CardAction();
+ cardAction.label = label;
+ cardAction.id = id;
+ cardAction.type = type;
+ mCardActions.add(cardAction);
+ }
+
+ /**
+ * Toggles the visibility of a card action.
+ * @param actionId
+ * @param isVisible
+ * @return
+ */
+ public Card setActionVisibility(int actionId, boolean isVisible) {
+ int visibilityFlag = isVisible ? View.VISIBLE : View.GONE;
+ for (CardAction action : mCardActions) {
+ if (action.id == actionId && action.actionView != null) {
+ action.actionView.setVisibility(visibilityFlag);
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Toggles visibility of the action area of this Card through an animation.
+ * @param isVisible
+ * @return
+ */
+ public Card setActionAreaVisibility(boolean isVisible) {
+ if (mActionAreaView == null) {
+ return this; // Card does not have an action area
+ }
+
+ if (isVisible) {
+ // Show the action area
+ mActionAreaView.setVisibility(View.VISIBLE);
+ mActionAreaView.setPivotY(0.f);
+ mActionAreaView.setPivotX(mCardView.getWidth() / 2.f);
+ mActionAreaView.setAlpha(0.5f);
+ mActionAreaView.setRotationX(-90.f);
+ mActionAreaView.animate().rotationX(0.f).alpha(1.f).setDuration(400);
+ } else {
+ // Hide the action area
+ mActionAreaView.setPivotY(0.f);
+ mActionAreaView.setPivotX(mCardView.getWidth() / 2.f);
+ mActionAreaView.animate().rotationX(-90.f).alpha(0.f).setDuration(400).setListener(
+ new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mActionAreaView.setVisibility(View.GONE);
+ }
+ });
+ }
+ return this;
+ }
+
+
+ /**
+ * Creates a shallow clone of the card. Shallow means all values are present, but no views.
+ * This is useful for saving/restoring in the case of configuration changes, like screen
+ * rotation.
+ *
+ * @return A shallow clone of the card instance
+ */
+ public Card createShallowClone() {
+ Card cloneCard = new Card();
+
+ // Outer card values
+ cloneCard.mTitle = mTitle;
+ cloneCard.mDescription = mDescription;
+ cloneCard.mTag = mTag;
+ cloneCard.mLayoutId = mLayoutId;
+ cloneCard.mCardState = mCardState;
+
+ // Progress
+ if (mCardProgress != null) {
+ cloneCard.mCardProgress = mCardProgress.createShallowClone();
+ }
+
+ // Actions
+ for (CardAction action : mCardActions) {
+ cloneCard.mCardActions.add(action.createShallowClone());
+ }
+
+ return cloneCard;
+ }
+
+
+ /**
+ * Prepare the card to be stored for configuration change.
+ */
+ public void prepareForConfigurationChange() {
+ // Null out views.
+ mCardView = null;
+ for (CardAction action : mCardActions) {
+ action.actionView = null;
+ }
+ mCardProgress.progressView = null;
+ }
+
+ /**
+ * Creates a new {@link #Card}.
+ */
+ public static class Builder {
+ private Card mCard;
+
+ /**
+ * Instantiate the builder with data from a shallow clone.
+ * @param listener
+ * @param card
+ * @see Card#createShallowClone()
+ */
+ protected Builder(OnCardClickListener listener, Card card) {
+ mCard = card;
+ mCard.mClickListener = listener;
+ }
+
+ /**
+ * Instantiate the builder with the tag of the card.
+ * @param listener
+ * @param tag
+ */
+ public Builder(OnCardClickListener listener, String tag) {
+ mCard = new Card();
+ mCard.mTag = tag;
+ mCard.mClickListener = listener;
+ }
+
+ public Builder setTitle(String title) {
+ mCard.mTitle = title;
+ return this;
+ }
+
+ public Builder setDescription(String desc) {
+ mCard.mDescription = desc;
+ return this;
+ }
+
+ /**
+ * Add an action.
+ * The type describes how this action will be displayed. Accepted values are
+ * {@link #ACTION_NEUTRAL}, {@link #ACTION_POSITIVE} or {@link #ACTION_NEGATIVE}.
+ *
+ * @param label The text to display for this action
+ * @param id Identifier for this action, supplied in the click listener
+ * @param type UI style of action
+ * @return
+ */
+ public Builder addAction(String label, int id, int type) {
+ mCard.addAction(label, id, type);
+ return this;
+ }
+
+ /**
+ * Override the default layout.
+ * The referenced layout file has to contain the same identifiers as defined in the default
+ * layout configuration.
+ * @param layout
+ * @return
+ * @see R.layout.card
+ */
+ public Builder setLayout(int layout) {
+ mCard.mLayoutId = layout;
+ return this;
+ }
+
+ /**
+ * Set the type of progress bar to display.
+ * Accepted values are:
+ * <ul>
+ * <li>{@link #PROGRESS_TYPE_NO_PROGRESS} disables the progress indicator</li>
+ * <li>{@link #PROGRESS_TYPE_NORMAL}
+ * displays a standard, linear progress indicator.</li>
+ * <li>{@link #PROGRESS_TYPE_INDETERMINATE} displays an indeterminate (infite) progress
+ * indicator.</li>
+ * <li>{@link #PROGRESS_TYPE_LABEL} only displays a label text in the progress area
+ * of the card.</li>
+ * </ul>
+ *
+ * @param progressType
+ * @return
+ */
+ public Builder setProgressType(int progressType) {
+ mCard.setProgressType(progressType);
+ return this;
+ }
+
+ public Builder setProgressLabel(String label) {
+ // ensure the progress layout has been initialized, use 'no progress' by default
+ if (mCard.mCardProgress == null) {
+ mCard.setProgressType(PROGRESS_TYPE_NO_PROGRESS);
+ }
+ mCard.mCardProgress.label = label;
+ return this;
+ }
+
+ public Builder setProgressMaxValue(int maxValue) {
+ // ensure the progress layout has been initialized, use 'no progress' by default
+ if (mCard.mCardProgress == null) {
+ mCard.setProgressType(PROGRESS_TYPE_NO_PROGRESS);
+ }
+ mCard.mCardProgress.maxValue = maxValue;
+ return this;
+ }
+
+ public Builder setStatus(int status) {
+ mCard.setState(status);
+ return this;
+ }
+
+ public Card build(Activity activity) {
+ LayoutInflater inflater = activity.getLayoutInflater();
+ // Inflating the card.
+ ViewGroup cardView = (ViewGroup) inflater.inflate(mCard.mLayoutId,
+ (ViewGroup) activity.findViewById(R.id.card_stream), false);
+
+ // Check that the layout contains a TextView with the card_title id
+ View viewTitle = cardView.findViewById(R.id.card_title);
+ if (mCard.mTitle != null && viewTitle != null) {
+ mCard.mTitleView = (TextView) viewTitle;
+ mCard.mTitleView.setText(mCard.mTitle);
+ } else if (viewTitle != null) {
+ viewTitle.setVisibility(View.GONE);
+ }
+
+ // Check that the layout contains a TextView with the card_content id
+ View viewDesc = cardView.findViewById(R.id.card_content);
+ if (mCard.mDescription != null && viewDesc != null) {
+ mCard.mDescView = (TextView) viewDesc;
+ mCard.mDescView.setText(mCard.mDescription);
+ } else if (viewDesc != null) {
+ cardView.findViewById(R.id.card_content).setVisibility(View.GONE);
+ }
+
+
+ ViewGroup actionArea = (ViewGroup) cardView.findViewById(R.id.card_actionarea);
+
+ // Inflate Progress
+ initializeProgressView(inflater, actionArea);
+
+ // Inflate all action views.
+ initializeActionViews(inflater, cardView, actionArea);
+
+ mCard.mCardView = cardView;
+ mCard.mOverlayView = cardView.findViewById(R.id.card_overlay);
+
+ return mCard;
+ }
+
+ /**
+ * Initialize data from the given card.
+ * @param card
+ * @return
+ * @see Card#createShallowClone()
+ */
+ public Builder cloneFromCard(Card card) {
+ mCard = card.createShallowClone();
+ return this;
+ }
+
+ /**
+ * Build the action views by inflating the appropriate layouts and setting the text and
+ * values.
+ * @param inflater
+ * @param cardView
+ * @param actionArea
+ */
+ private void initializeActionViews(LayoutInflater inflater, ViewGroup cardView,
+ ViewGroup actionArea) {
+ if (!mCard.mCardActions.isEmpty()) {
+ // Set action area to visible only when actions are visible
+ actionArea.setVisibility(View.VISIBLE);
+ mCard.mActionAreaView = actionArea;
+ }
+
+ // Inflate all card actions
+ for (final CardAction action : mCard.mCardActions) {
+
+ int useActionLayout = 0;
+ switch (action.type) {
+ case Card.ACTION_POSITIVE:
+ useActionLayout = R.layout.card_button_positive;
+ break;
+ case Card.ACTION_NEGATIVE:
+ useActionLayout = R.layout.card_button_negative;
+ break;
+ case Card.ACTION_NEUTRAL:
+ default:
+ useActionLayout = R.layout.card_button_neutral;
+ break;
+ }
+
+ action.actionView = inflater.inflate(useActionLayout, actionArea, false);
+ Button actionButton = (Button) action.actionView.findViewById(R.id.card_button);
+
+ actionButton.setText(action.label);
+ actionButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mCard.mClickListener.onCardClick(action.id, mCard.mTag);
+ }
+ });
+ actionArea.addView(action.actionView);
+ }
+ }
+
+ /**
+ * Build the progress view into the given ViewGroup.
+ *
+ * @param inflater
+ * @param actionArea
+ */
+ private void initializeProgressView(LayoutInflater inflater, ViewGroup actionArea) {
+
+ // Only inflate progress layout if a progress type other than NO_PROGRESS was set.
+ if (mCard.mCardProgress != null) {
+ //Setup progress card.
+ View progressView = inflater.inflate(R.layout.card_progress, actionArea, false);
+ ProgressBar progressBar =
+ (ProgressBar) progressView.findViewById(R.id.card_progress);
+ ((TextView) progressView.findViewById(R.id.card_progress_text))
+ .setText(mCard.mCardProgress.label);
+ progressBar.setMax(mCard.mCardProgress.maxValue);
+ progressBar.setProgress(0);
+ mCard.mCardProgress.progressView = progressView;
+ mCard.mCardProgress.setProgressType(mCard.getProgressType());
+ actionArea.addView(progressView);
+ }
+ }
+ }
+
+ /**
+ * Represents a clickable action, accessible from the bottom of the card.
+ * Fields include the label, an ID to specify the action that was performed in the callback,
+ * an action type (positive, negative, neutral), and the callback.
+ */
+ public class CardAction {
+
+ public String label;
+ public int id;
+ public int type;
+ public View actionView;
+
+ public CardAction createShallowClone() {
+ CardAction actionClone = new CardAction();
+ actionClone.label = label;
+ actionClone.id = id;
+ actionClone.type = type;
+ return actionClone;
+ // Not the view. Never the view (don't want to hold view references for
+ // onConfigurationChange.
+ }
+
+ }
+
+ /**
+ * Describes the progress of a {@link Card}.
+ * Three types of progress are supported:
+ * <ul><li>{@link Card#PROGRESS_TYPE_NORMAL: Standard progress bar with label text</li>
+ * <li>{@link Card#PROGRESS_TYPE_INDETERMINATE}: Indeterminate progress bar with label txt</li>
+ * <li>{@link Card#PROGRESS_TYPE_LABEL}: Label only, no progresss bar</li>
+ * </ul>
+ */
+ public class CardProgress {
+ private int progressType = Card.PROGRESS_TYPE_NO_PROGRESS;
+ private String label = "";
+ private int currProgress = 0;
+ private int maxValue = 100;
+
+ public View progressView = null;
+ private ProgressBar progressBar = null;
+ private TextView progressLabel = null;
+
+ public CardProgress createShallowClone() {
+ CardProgress progressClone = new CardProgress();
+ progressClone.label = label;
+ progressClone.currProgress = currProgress;
+ progressClone.maxValue = maxValue;
+ progressClone.progressType = progressType;
+ return progressClone;
+ }
+
+ /**
+ * Set the progress. Only useful for the type {@link #PROGRESS_TYPE_NORMAL}.
+ * @param progress
+ * @see android.widget.ProgressBar#setProgress(int)
+ */
+ public void setProgress(int progress) {
+ currProgress = progress;
+ final ProgressBar bar = getProgressBar();
+ if (bar != null) {
+ bar.setProgress(currProgress);
+ bar.invalidate();
+ }
+ }
+
+ /**
+ * Set the range of the progress to 0...max.
+ * Only useful for the type {@link #PROGRESS_TYPE_NORMAL}.
+ * @param max
+ * @see android.widget.ProgressBar#setMax(int)
+ */
+ public void setMax(int max) {
+ maxValue = max;
+ final ProgressBar bar = getProgressBar();
+ if (bar != null) {
+ bar.setMax(maxValue);
+ }
+ }
+
+ /**
+ * Set the label text that appears near the progress indicator.
+ * @param text
+ */
+ public void setProgressLabel(String text) {
+ label = text;
+ final TextView labelView = getProgressLabel();
+ if (labelView != null) {
+ labelView.setText(text);
+ }
+ }
+
+ /**
+ * Set how progress is displayed. The parameter must be one of three supported types:
+ * <ul><li>{@link Card#PROGRESS_TYPE_NORMAL: Standard progress bar with label text</li>
+ * <li>{@link Card#PROGRESS_TYPE_INDETERMINATE}:
+ * Indeterminate progress bar with label txt</li>
+ * <li>{@link Card#PROGRESS_TYPE_LABEL}: Label only, no progresss bar</li>
+ * @param type
+ */
+ public void setProgressType(int type) {
+ progressType = type;
+ if (progressView != null) {
+ switch (type) {
+ case PROGRESS_TYPE_NO_PROGRESS: {
+ progressView.setVisibility(View.GONE);
+ break;
+ }
+ case PROGRESS_TYPE_NORMAL: {
+ progressView.setVisibility(View.VISIBLE);
+ getProgressBar().setIndeterminate(false);
+ break;
+ }
+ case PROGRESS_TYPE_INDETERMINATE: {
+ progressView.setVisibility(View.VISIBLE);
+ getProgressBar().setIndeterminate(true);
+ break;
+ }
+ }
+ }
+ }
+
+ private TextView getProgressLabel() {
+ if (progressLabel != null) {
+ return progressLabel;
+ } else if (progressView != null) {
+ progressLabel = (TextView) progressView.findViewById(R.id.card_progress_text);
+ return progressLabel;
+ } else {
+ return null;
+ }
+ }
+
+ private ProgressBar getProgressBar() {
+ if (progressBar != null) {
+ return progressBar;
+ } else if (progressView != null) {
+ progressBar = (ProgressBar) progressView.findViewById(R.id.card_progress);
+ return progressBar;
+ } else {
+ return null;
+ }
+ }
+
+ }
+}
+
diff --git a/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardActionButton.java b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardActionButton.java
new file mode 100644
index 000000000..ea37e6601
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardActionButton.java
@@ -0,0 +1,69 @@
+/*
+* Copyright 2013 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.example.android.batchstepsensor;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.animation.BounceInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.widget.Button;
+
+/**
+ * Custom Button with a special 'pressed' effect for touch events.
+ */
+public class CardActionButton extends Button {
+
+ public CardActionButton(Context context) {
+ super(context);
+ }
+
+ public CardActionButton(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public CardActionButton(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+
+ switch(event.getAction()){
+ case MotionEvent.ACTION_DOWN:
+ setPressed(true);
+ animate().scaleX(0.98f).scaleY(0.98f).alpha(0.8f).setDuration(100).
+ setInterpolator(new DecelerateInterpolator());
+ break;
+ case MotionEvent.ACTION_UP:
+ animate().scaleX(1.0f).scaleY(1.f).alpha(1.0f).setDuration(50).
+ setInterpolator(new BounceInterpolator());
+ break;
+ case MotionEvent.ACTION_CANCEL:
+ animate().scaleX(1.0f).scaleY(1.f).alpha(1.0f).setDuration(50).
+ setInterpolator(new BounceInterpolator());
+ break;
+ }
+
+ return super.onTouchEvent(event);
+ }
+
+}
+
diff --git a/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardLayout.java b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardLayout.java
new file mode 100644
index 000000000..821527505
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardLayout.java
@@ -0,0 +1,94 @@
+/*
+* Copyright 2013 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.example.android.batchstepsensor;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+import android.widget.RelativeLayout;
+
+/**
+ * Custom Button with a special 'pressed' effect for touch events.
+ */
+public class CardLayout extends RelativeLayout {
+
+ private boolean mSwiping = false;
+ private float mDownX = 0.f;
+ private float mDownY = 0.f;
+ private float mTouchSlop = 0.f;
+
+ public CardLayout(Context context) {
+ super(context);
+ init();
+ }
+
+ public CardLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ public CardLayout(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init();
+ }
+
+ private void init(){
+ setFocusable(true);
+ setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
+ setWillNotDraw(false);
+ setClickable(true);
+
+ mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop() * 2.f;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ switch(event.getAction()){
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+ mSwiping = false;
+ break;
+ }
+ return super.onTouchEvent(event);
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent event) {
+
+ switch(event.getAction()){
+ case MotionEvent.ACTION_MOVE:
+ if( !mSwiping ){
+ mSwiping = Math.abs(mDownX - event.getX()) > mTouchSlop;
+ }
+ break;
+ case MotionEvent.ACTION_DOWN:
+ mDownX = event.getX();
+ mDownY = event.getY();
+ mSwiping = false;
+ break;
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+ mSwiping = false;
+ break;
+ }
+ return mSwiping;
+ }
+} \ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStream.java b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStream.java
new file mode 100644
index 000000000..5de985223
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStream.java
@@ -0,0 +1,25 @@
+/*
+* Copyright 2013 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.example.android.batchstepsensor;
+
+public interface CardStream {
+ public CardStreamFragment getCardStream();
+}
+
diff --git a/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStreamAnimator.java b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStreamAnimator.java
new file mode 100644
index 000000000..a22ddd7d4
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStreamAnimator.java
@@ -0,0 +1,120 @@
+/*
+* Copyright 2013 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.example.android.batchstepsensor;
+
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.view.View;
+
+/**
+ * An abstract class which defines animators for CardStreamLinearLayout.
+ */
+abstract class CardStreamAnimator {
+
+ protected float mSpeedFactor = 1.f;
+
+ /**
+ * Set speed factor of animations. Higher value means longer duration & slow animation.
+ *
+ * @param speedFactor speed type 1: SLOW, 2: NORMAL, 3:FAST
+ */
+ public void setSpeedFactor(float speedFactor) {
+ mSpeedFactor = speedFactor;
+ }
+
+ /**
+ * Define initial animation of each child which fired when a user rotate a screen.
+ *
+ * @param context
+ * @return ObjectAnimator for initial animation
+ */
+ public abstract ObjectAnimator getInitalAnimator(Context context);
+
+ /**
+ * Define disappearing animation of a child which fired when a view is removed programmatically
+ *
+ * @param context
+ * @return ObjectAnimator for disappearing animation
+ */
+ public abstract ObjectAnimator getDisappearingAnimator(Context context);
+
+ /**
+ * Define appearing animation of a child which fired when a view is added programmatically
+ *
+ * @param context
+ * @return ObjectAnimator for appearing animation
+ */
+ public abstract ObjectAnimator getAppearingAnimator(Context context);
+
+ /**
+ * Define swipe-in (back to the origin position) animation of a child
+ * which fired when a view is not moved enough to be removed.
+ *
+ * @param view target view
+ * @param deltaX delta distance by x-axis
+ * @param deltaY delta distance by y-axis
+ * @return ObjectAnimator for swipe-in animation
+ */
+ public abstract ObjectAnimator getSwipeInAnimator(View view, float deltaX, float deltaY);
+
+ /**
+ * Define swipe-out animation of a child
+ * which fired when a view is removing by a user swipe action.
+ *
+ * @param view target view
+ * @param deltaX delta distance by x-axis
+ * @param deltaY delta distance by y-axis
+ * @return ObjectAnimator for swipe-out animation
+ */
+ public abstract ObjectAnimator getSwipeOutAnimator(View view, float deltaX, float deltaY);
+
+ /**
+ * A simple CardStreamAnimator implementation which is used to turn animations off.
+ */
+ public static class EmptyAnimator extends CardStreamAnimator {
+
+ @Override
+ public ObjectAnimator getInitalAnimator(Context context) {
+ return null;
+ }
+
+ @Override
+ public ObjectAnimator getDisappearingAnimator(Context context) {
+ return null;
+ }
+
+ @Override
+ public ObjectAnimator getAppearingAnimator(Context context) {
+ return null;
+ }
+
+ @Override
+ public ObjectAnimator getSwipeInAnimator(View view, float deltaX, float deltaY) {
+ return null;
+ }
+
+ @Override
+ public ObjectAnimator getSwipeOutAnimator(View view, float deltaX, float deltaY) {
+ return null;
+ }
+ }
+
+}
+
diff --git a/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStreamFragment.java b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStreamFragment.java
new file mode 100644
index 000000000..9f8b7cb4f
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStreamFragment.java
@@ -0,0 +1,275 @@
+/*
+* Copyright 2013 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.example.android.batchstepsensor;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+
+
+/**
+ * A Fragment that handles a stream of cards.
+ * Cards can be shown or hidden. When a card is shown it can also be marked as not-dismissible, see
+ * {@link CardStreamLinearLayout#addCard(android.view.View, boolean)}.
+ */
+public class CardStreamFragment extends Fragment {
+
+ private static final int INITIAL_SIZE = 15;
+ private CardStreamLinearLayout mLayout = null;
+ private LinkedHashMap<String, Card> mVisibleCards = new LinkedHashMap<String, Card>(INITIAL_SIZE);
+ private HashMap<String, Card> mHiddenCards = new HashMap<String, Card>(INITIAL_SIZE);
+ private HashSet<String> mDismissibleCards = new HashSet<String>(INITIAL_SIZE);
+
+ // Set the listener to handle dismissed cards by moving them to the hidden cards map.
+ private CardStreamLinearLayout.OnDissmissListener mCardDismissListener =
+ new CardStreamLinearLayout.OnDissmissListener() {
+ @Override
+ public void onDismiss(String tag) {
+ dismissCard(tag);
+ }
+ };
+
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+
+ View view = inflater.inflate(R.layout.cardstream, container, false);
+ mLayout = (CardStreamLinearLayout) view.findViewById(R.id.card_stream);
+ mLayout.setOnDismissListener(mCardDismissListener);
+
+ return view;
+ }
+
+ /**
+ * Add a visible, dismissible card to the card stream.
+ *
+ * @param card
+ */
+ public void addCard(Card card) {
+ final String tag = card.getTag();
+
+ if (!mVisibleCards.containsKey(tag) && !mHiddenCards.containsKey(tag)) {
+ final View view = card.getView();
+ view.setTag(tag);
+ mHiddenCards.put(tag, card);
+ }
+ }
+
+ /**
+ * Add and show a card.
+ *
+ * @param card
+ * @param show
+ */
+ public void addCard(Card card, boolean show) {
+ addCard(card);
+ if (show) {
+ showCard(card.getTag());
+ }
+ }
+
+ /**
+ * Remove a card and return true if it has been successfully removed.
+ *
+ * @param tag
+ * @return
+ */
+ public boolean removeCard(String tag) {
+ // Attempt to remove a visible card first
+ Card card = mVisibleCards.get(tag);
+ if (card != null) {
+ // Card is visible, also remove from layout
+ mVisibleCards.remove(tag);
+ mLayout.removeView(card.getView());
+ return true;
+ } else {
+ // Card is hidden, no need to remove from layout
+ card = mHiddenCards.remove(tag);
+ return card != null;
+ }
+ }
+
+ /**
+ * Show a dismissible card, returns false if the card could not be shown.
+ *
+ * @param tag
+ * @return
+ */
+ public boolean showCard(String tag) {
+ return showCard(tag, true);
+ }
+
+ /**
+ * Show a card, returns false if the card could not be shown.
+ *
+ * @param tag
+ * @param dismissible
+ * @return
+ */
+ public boolean showCard(String tag, boolean dismissible) {
+ final Card card = mHiddenCards.get(tag);
+ // ensure the card is hidden and not already visible
+ if (card != null && !mVisibleCards.containsValue(tag)) {
+ mHiddenCards.remove(tag);
+ mVisibleCards.put(tag, card);
+ mLayout.addCard(card.getView(), dismissible);
+ if (dismissible) {
+ mDismissibleCards.add(tag);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Hides the card, returns false if the card could not be hidden.
+ *
+ * @param tag
+ * @return
+ */
+ public boolean hideCard(String tag) {
+ final Card card = mVisibleCards.get(tag);
+ if (card != null) {
+ mVisibleCards.remove(tag);
+ mDismissibleCards.remove(tag);
+ mHiddenCards.put(tag, card);
+
+ mLayout.removeView(card.getView());
+ return true;
+ }
+ return mHiddenCards.containsValue(tag);
+ }
+
+
+ private void dismissCard(String tag) {
+ final Card card = mVisibleCards.get(tag);
+ if (card != null) {
+ mDismissibleCards.remove(tag);
+ mVisibleCards.remove(tag);
+ mHiddenCards.put(tag, card);
+ }
+ }
+
+
+ public boolean isCardVisible(String tag) {
+ return mVisibleCards.containsValue(tag);
+ }
+
+ /**
+ * Returns true if the card is shown and is dismissible.
+ *
+ * @param tag
+ * @return
+ */
+ public boolean isCardDismissible(String tag) {
+ return mDismissibleCards.contains(tag);
+ }
+
+ /**
+ * Returns the Card for this tag.
+ *
+ * @param tag
+ * @return
+ */
+ public Card getCard(String tag) {
+ final Card card = mVisibleCards.get(tag);
+ if (card != null) {
+ return card;
+ } else {
+ return mHiddenCards.get(tag);
+ }
+ }
+
+ /**
+ * Moves the view port to show the card with this tag.
+ *
+ * @param tag
+ * @see CardStreamLinearLayout#setFirstVisibleCard(String)
+ */
+ public void setFirstVisibleCard(String tag) {
+ final Card card = mVisibleCards.get(tag);
+ if (card != null) {
+ mLayout.setFirstVisibleCard(tag);
+ }
+ }
+
+ public int getVisibleCardCount() {
+ return mVisibleCards.size();
+ }
+
+ public Collection<Card> getVisibleCards() {
+ return mVisibleCards.values();
+ }
+
+ public void restoreState(CardStreamState state, OnCardClickListener callback) {
+ // restore hidden cards
+ for (Card c : state.hiddenCards) {
+ Card card = new Card.Builder(callback,c).build(getActivity());
+ mHiddenCards.put(card.getTag(), card);
+ }
+
+ // temporarily set up list of dismissible
+ final HashSet<String> dismissibleCards = state.dismissibleCards;
+
+ //restore shown cards
+ for (Card c : state.visibleCards) {
+ Card card = new Card.Builder(callback,c).build(getActivity());
+ addCard(card);
+ final String tag = card.getTag();
+ showCard(tag, dismissibleCards.contains(tag));
+ }
+
+ // move to first visible card
+ final String firstShown = state.shownTag;
+ if (firstShown != null) {
+ mLayout.setFirstVisibleCard(firstShown);
+ }
+
+ mLayout.triggerShowInitialAnimation();
+ }
+
+ public CardStreamState dumpState() {
+ final Card[] visible = cloneCards(mVisibleCards.values());
+ final Card[] hidden = cloneCards(mHiddenCards.values());
+ final HashSet<String> dismissible = new HashSet<String>(mDismissibleCards);
+ final String firstVisible = mLayout.getFirstVisibleCardTag();
+
+ return new CardStreamState(visible, hidden, dismissible, firstVisible);
+ }
+
+ private Card[] cloneCards(Collection<Card> cards) {
+ Card[] cardArray = new Card[cards.size()];
+ int i = 0;
+ for (Card c : cards) {
+ cardArray[i++] = c.createShallowClone();
+ }
+
+ return cardArray;
+ }
+
+}
diff --git a/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStreamLinearLayout.java b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStreamLinearLayout.java
new file mode 100644
index 000000000..aeab77080
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStreamLinearLayout.java
@@ -0,0 +1,569 @@
+/*
+* Copyright 2013 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.example.android.batchstepsensor;
+
+import android.animation.Animator;
+import android.animation.LayoutTransition;
+import android.animation.ObjectAnimator;
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Rect;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+
+import com.example.android.common.logger.Log;
+
+import java.util.ArrayList;
+
+/**
+ * A Layout that contains a stream of card views.
+ */
+public class CardStreamLinearLayout extends LinearLayout {
+
+ public static final int ANIMATION_SPEED_SLOW = 1001;
+ public static final int ANIMATION_SPEED_NORMAL = 1002;
+ public static final int ANIMATION_SPEED_FAST = 1003;
+
+ private static final String TAG = "CardStreamLinearLayout";
+ private final ArrayList<View> mFixedViewList = new ArrayList<View>();
+ private final Rect mChildRect = new Rect();
+ private CardStreamAnimator mAnimators;
+ private OnDissmissListener mDismissListener = null;
+ private boolean mLayouted = false;
+ private boolean mSwiping = false;
+ private String mFirstVisibleCardTag = null;
+ private boolean mShowInitialAnimation = false;
+
+ /**
+ * Handle touch events to fade/move dragged items as they are swiped out
+ */
+ private OnTouchListener mTouchListener = new OnTouchListener() {
+
+ private float mDownX;
+ private float mDownY;
+
+ @Override
+ public boolean onTouch(final View v, MotionEvent event) {
+
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ mDownX = event.getX();
+ mDownY = event.getY();
+ break;
+ case MotionEvent.ACTION_CANCEL:
+ resetAnimatedView(v);
+ mSwiping = false;
+ mDownX = 0.f;
+ mDownY = 0.f;
+ break;
+ case MotionEvent.ACTION_MOVE: {
+
+ float x = event.getX() + v.getTranslationX();
+ float y = event.getY() + v.getTranslationY();
+
+ mDownX = mDownX == 0.f ? x : mDownX;
+ mDownY = mDownY == 0.f ? x : mDownY;
+
+ float deltaX = x - mDownX;
+ float deltaY = y - mDownY;
+
+ if (!mSwiping && isSwiping(deltaX, deltaY)) {
+ mSwiping = true;
+ v.getParent().requestDisallowInterceptTouchEvent(true);
+ } else {
+ swipeView(v, deltaX, deltaY);
+ }
+ }
+ break;
+ case MotionEvent.ACTION_UP: {
+ // User let go - figure out whether to animate the view out, or back into place
+ if (mSwiping) {
+ float x = event.getX() + v.getTranslationX();
+ float y = event.getY() + v.getTranslationY();
+
+ float deltaX = x - mDownX;
+ float deltaY = y - mDownX;
+ float deltaXAbs = Math.abs(deltaX);
+
+ // User let go - figure out whether to animate the view out, or back into place
+ boolean remove = deltaXAbs > v.getWidth() / 4 && !isFixedView(v);
+ if( remove )
+ handleViewSwipingOut(v, deltaX, deltaY);
+ else
+ handleViewSwipingIn(v, deltaX, deltaY);
+ }
+ mDownX = 0.f;
+ mDownY = 0.f;
+ mSwiping = false;
+ }
+ break;
+ default:
+ return false;
+ }
+ return false;
+ }
+ };
+ private int mSwipeSlop = -1;
+ /**
+ * Handle end-transition animation event of each child and launch a following animation.
+ */
+ private LayoutTransition.TransitionListener mTransitionListener
+ = new LayoutTransition.TransitionListener() {
+
+ @Override
+ public void startTransition(LayoutTransition transition, ViewGroup container, View
+ view, int transitionType) {
+ Log.d(TAG, "Start LayoutTransition animation:" + transitionType);
+ }
+
+ @Override
+ public void endTransition(LayoutTransition transition, ViewGroup container,
+ final View view, int transitionType) {
+
+ Log.d(TAG, "End LayoutTransition animation:" + transitionType);
+ if (transitionType == LayoutTransition.APPEARING) {
+ final View area = view.findViewById(R.id.card_actionarea);
+ if (area != null) {
+ runShowActionAreaAnimation(container, area);
+ }
+ }
+ }
+ };
+ /**
+ * Handle a hierarchy change event
+ * when a new child is added, scroll to bottom and hide action area..
+ */
+ private OnHierarchyChangeListener mOnHierarchyChangeListener
+ = new OnHierarchyChangeListener() {
+ @Override
+ public void onChildViewAdded(final View parent, final View child) {
+
+ Log.d(TAG, "child is added: " + child);
+
+ ViewParent scrollView = parent.getParent();
+ if (scrollView != null && scrollView instanceof ScrollView) {
+ ((ScrollView) scrollView).fullScroll(FOCUS_DOWN);
+ }
+
+ if (getLayoutTransition() != null) {
+ View view = child.findViewById(R.id.card_actionarea);
+ if (view != null)
+ view.setAlpha(0.f);
+ }
+ }
+
+ @Override
+ public void onChildViewRemoved(View parent, View child) {
+ Log.d(TAG, "child is removed: " + child);
+ mFixedViewList.remove(child);
+ }
+ };
+ private int mLastDownX;
+
+ public CardStreamLinearLayout(Context context) {
+ super(context);
+ initialize(null, 0);
+ }
+
+ public CardStreamLinearLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ initialize(attrs, 0);
+ }
+
+ @SuppressLint("NewApi")
+ public CardStreamLinearLayout(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ initialize(attrs, defStyle);
+ }
+
+ /**
+ * add a card view w/ canDismiss flag.
+ *
+ * @param cardView a card view
+ * @param canDismiss flag to indicate this card is dismissible or not.
+ */
+ public void addCard(View cardView, boolean canDismiss) {
+ if (cardView.getParent() == null) {
+ initCard(cardView, canDismiss);
+
+ ViewGroup.LayoutParams param = cardView.getLayoutParams();
+ if(param == null)
+ param = generateDefaultLayoutParams();
+
+ super.addView(cardView, -1, param);
+ }
+ }
+
+ @Override
+ public void addView(View child, int index, ViewGroup.LayoutParams params) {
+ if (child.getParent() == null) {
+ initCard(child, true);
+ super.addView(child, index, params);
+ }
+ }
+
+ @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+ Log.d(TAG, "onLayout: " + changed);
+
+ if( changed && !mLayouted ){
+ mLayouted = true;
+
+ ObjectAnimator animator;
+ LayoutTransition layoutTransition = new LayoutTransition();
+
+ animator = mAnimators.getDisappearingAnimator(getContext());
+ layoutTransition.setAnimator(LayoutTransition.DISAPPEARING, animator);
+
+ animator = mAnimators.getAppearingAnimator(getContext());
+ layoutTransition.setAnimator(LayoutTransition.APPEARING, animator);
+
+ layoutTransition.addTransitionListener(mTransitionListener);
+
+ if( animator != null )
+ layoutTransition.setDuration(animator.getDuration());
+
+ setLayoutTransition(layoutTransition);
+
+ if( mShowInitialAnimation )
+ runInitialAnimations();
+
+ if (mFirstVisibleCardTag != null) {
+ scrollToCard(mFirstVisibleCardTag);
+ mFirstVisibleCardTag = null;
+ }
+ }
+ }
+
+ /**
+ * Check whether a user moved enough distance to start a swipe action or not.
+ *
+ * @param deltaX
+ * @param deltaY
+ * @return true if a user is swiping.
+ */
+ protected boolean isSwiping(float deltaX, float deltaY) {
+
+ if (mSwipeSlop < 0) {
+ //get swipping slop from ViewConfiguration;
+ mSwipeSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
+ }
+
+ boolean swipping = false;
+ float absDeltaX = Math.abs(deltaX);
+
+ if( absDeltaX > mSwipeSlop )
+ return true;
+
+ return swipping;
+ }
+
+ /**
+ * Swipe a view by moving distance
+ *
+ * @param child a target view
+ * @param deltaX x moving distance by x-axis.
+ * @param deltaY y moving distance by y-axis.
+ */
+ @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+ protected void swipeView(View child, float deltaX, float deltaY) {
+ if (isFixedView(child)){
+ deltaX = deltaX / 4;
+ }
+
+ float deltaXAbs = Math.abs(deltaX);
+ float fractionCovered = deltaXAbs / (float) child.getWidth();
+
+ child.setTranslationX(deltaX);
+ child.setAlpha(1.f - fractionCovered);
+
+ if (deltaX > 0)
+ child.setRotationY(-15.f * fractionCovered);
+ else
+ child.setRotationY(15.f * fractionCovered);
+ }
+
+ protected void notifyOnDismissEvent( View child ){
+ if( child == null || mDismissListener == null )
+ return;
+
+ mDismissListener.onDismiss((String) child.getTag());
+ }
+
+ /**
+ * get the tag of the first visible child in this layout
+ *
+ * @return tag of the first visible child or null
+ */
+ public String getFirstVisibleCardTag() {
+
+ final int count = getChildCount();
+
+ if (count == 0)
+ return null;
+
+ for (int index = 0; index < count; ++index) {
+ //check the position of each view.
+ View child = getChildAt(index);
+ if (child.getGlobalVisibleRect(mChildRect) == true)
+ return (String) child.getTag();
+ }
+
+ return null;
+ }
+
+ /**
+ * Set the first visible card of this linear layout.
+ *
+ * @param tag tag of a card which should already added to this layout.
+ */
+ public void setFirstVisibleCard(String tag) {
+ if (tag == null)
+ return; //do nothing.
+
+ if (mLayouted) {
+ scrollToCard(tag);
+ } else {
+ //keep the tag for next use.
+ mFirstVisibleCardTag = tag;
+ }
+ }
+
+ /**
+ * If this flag is set,
+ * after finishing initial onLayout event, an initial animation which is defined in DefaultCardStreamAnimator is launched.
+ */
+ public void triggerShowInitialAnimation(){
+ mShowInitialAnimation = true;
+ }
+
+ @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+ public void setCardStreamAnimator( CardStreamAnimator animators ){
+
+ if( animators == null )
+ mAnimators = new CardStreamAnimator.EmptyAnimator();
+ else
+ mAnimators = animators;
+
+ LayoutTransition layoutTransition = getLayoutTransition();
+
+ if( layoutTransition != null ){
+ layoutTransition.setAnimator( LayoutTransition.APPEARING,
+ mAnimators.getAppearingAnimator(getContext()) );
+ layoutTransition.setAnimator( LayoutTransition.DISAPPEARING,
+ mAnimators.getDisappearingAnimator(getContext()) );
+ }
+ }
+
+ /**
+ * set a OnDismissListener which called when user dismiss a card.
+ *
+ * @param listener
+ */
+ public void setOnDismissListener(OnDissmissListener listener) {
+ mDismissListener = listener;
+ }
+
+ @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+ private void initialize(AttributeSet attrs, int defStyle) {
+
+ float speedFactor = 1.f;
+
+ if (attrs != null) {
+ TypedArray a = getContext().obtainStyledAttributes(attrs,
+ R.styleable.CardStream, defStyle, 0);
+
+ if( a != null ){
+ int speedType = a.getInt(R.styleable.CardStream_animationDuration, 1001);
+ switch (speedType){
+ case ANIMATION_SPEED_FAST:
+ speedFactor = 0.5f;
+ break;
+ case ANIMATION_SPEED_NORMAL:
+ speedFactor = 1.f;
+ break;
+ case ANIMATION_SPEED_SLOW:
+ speedFactor = 2.f;
+ break;
+ }
+
+ String animatorName = a.getString(R.styleable.CardStream_animators);
+
+ try {
+ if( animatorName != null )
+ mAnimators = (CardStreamAnimator) getClass().getClassLoader()
+ .loadClass(animatorName).newInstance();
+ } catch (Exception e) {
+ Log.e(TAG, "Fail to load animator:" + animatorName, e);
+ } finally {
+ if(mAnimators == null)
+ mAnimators = new DefaultCardStreamAnimator();
+ }
+ a.recycle();
+ }
+ }
+
+ mAnimators.setSpeedFactor(speedFactor);
+ mSwipeSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
+ setOnHierarchyChangeListener(mOnHierarchyChangeListener);
+ }
+
+ private void initCard(View cardView, boolean canDismiss) {
+ resetAnimatedView(cardView);
+ cardView.setOnTouchListener(mTouchListener);
+ if (!canDismiss)
+ mFixedViewList.add(cardView);
+ }
+
+ private boolean isFixedView(View v) {
+ return mFixedViewList.contains(v);
+ }
+
+ private void resetAnimatedView(View child) {
+ child.setAlpha(1.f);
+ child.setTranslationX(0.f);
+ child.setTranslationY(0.f);
+ child.setRotation(0.f);
+ child.setRotationY(0.f);
+ child.setRotationX(0.f);
+ child.setScaleX(1.f);
+ child.setScaleY(1.f);
+ }
+
+ @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+ private void runInitialAnimations() {
+ if( mAnimators == null )
+ return;
+
+ final int count = getChildCount();
+
+ for (int index = 0; index < count; ++index) {
+ final View child = getChildAt(index);
+ ObjectAnimator animator = mAnimators.getInitalAnimator(getContext());
+ if( animator != null ){
+ animator.setTarget(child);
+ animator.start();
+ }
+ }
+ }
+
+ private void runShowActionAreaAnimation(View parent, View area) {
+ area.setPivotY(0.f);
+ area.setPivotX(parent.getWidth() / 2.f);
+
+ area.setAlpha(0.5f);
+ area.setRotationX(-90.f);
+ area.animate().rotationX(0.f).alpha(1.f).setDuration(400);
+ }
+
+ private void handleViewSwipingOut(final View child, float deltaX, float deltaY) {
+ ObjectAnimator animator = mAnimators.getSwipeOutAnimator(child, deltaX, deltaY);
+ if( animator != null ){
+ animator.addListener(new EndAnimationWrapper() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ removeView(child);
+ notifyOnDismissEvent(child);
+ }
+ });
+ } else {
+ removeView(child);
+ notifyOnDismissEvent(child);
+ }
+
+ if( animator != null ){
+ animator.setTarget(child);
+ animator.start();
+ }
+ }
+
+ private void handleViewSwipingIn(final View child, float deltaX, float deltaY) {
+ ObjectAnimator animator = mAnimators.getSwipeInAnimator(child, deltaX, deltaY);
+ if( animator != null ){
+ animator.addListener(new EndAnimationWrapper() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ child.setTranslationY(0.f);
+ child.setTranslationX(0.f);
+ }
+ });
+ } else {
+ child.setTranslationY(0.f);
+ child.setTranslationX(0.f);
+ }
+
+ if( animator != null ){
+ animator.setTarget(child);
+ animator.start();
+ }
+ }
+
+ private void scrollToCard(String tag) {
+
+
+ final int count = getChildCount();
+ for (int index = 0; index < count; ++index) {
+ View child = getChildAt(index);
+
+ if (tag.equals(child.getTag())) {
+
+ ViewParent parent = getParent();
+ if( parent != null && parent instanceof ScrollView ){
+ ((ScrollView)parent).smoothScrollTo(
+ 0, child.getTop() - getPaddingTop() - child.getPaddingTop());
+ }
+ return;
+ }
+ }
+ }
+
+ public interface OnDissmissListener {
+ public void onDismiss(String tag);
+ }
+
+ /**
+ * Empty default AnimationListener
+ */
+ private abstract class EndAnimationWrapper implements Animator.AnimatorListener {
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ }
+ }//end of inner class
+}
diff --git a/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStreamState.java b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStreamState.java
new file mode 100644
index 000000000..08432a9a5
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStreamState.java
@@ -0,0 +1,40 @@
+/*
+* Copyright 2013 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.example.android.batchstepsensor;
+
+import java.util.HashSet;
+
+/**
+ * A struct object that holds the state of a {@link CardStreamFragment}.
+ */
+class CardStreamState{
+ protected Card[] visibleCards;
+ protected Card[] hiddenCards;
+ protected HashSet<String> dismissibleCards;
+ protected String shownTag;
+
+ protected CardStreamState(Card[] visible, Card[] hidden, HashSet<String> dismissible, String shownTag) {
+ visibleCards = visible;
+ hiddenCards = hidden;
+ dismissibleCards = dismissible;
+ this.shownTag = shownTag;
+ }
+
+}
diff --git a/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/DefaultCardStreamAnimator.java b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/DefaultCardStreamAnimator.java
new file mode 100644
index 000000000..19ef43bb9
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/DefaultCardStreamAnimator.java
@@ -0,0 +1,124 @@
+/*
+* Copyright 2013 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.example.android.batchstepsensor;
+
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.Point;
+import android.os.Build;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.animation.BounceInterpolator;
+
+class DefaultCardStreamAnimator extends CardStreamAnimator {
+
+ @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+ @Override
+ public ObjectAnimator getDisappearingAnimator(Context context){
+
+ ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(new Object(),
+ PropertyValuesHolder.ofFloat("alpha", 1.f, 0.f),
+ PropertyValuesHolder.ofFloat("scaleX", 1.f, 0.f),
+ PropertyValuesHolder.ofFloat("scaleY", 1.f, 0.f),
+ PropertyValuesHolder.ofFloat("rotation", 0.f, 270.f));
+
+ animator.setDuration((long) (200 * mSpeedFactor));
+ return animator;
+ }
+
+ @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
+ @Override
+ public ObjectAnimator getAppearingAnimator(Context context){
+
+ final Point outPoint = new Point();
+ WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+ wm.getDefaultDisplay().getSize(outPoint);
+
+ ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(new Object(),
+ PropertyValuesHolder.ofFloat("alpha", 0.f, 1.f),
+ PropertyValuesHolder.ofFloat("translationY", outPoint.y / 2.f, 0.f),
+ PropertyValuesHolder.ofFloat("rotation", -45.f, 0.f));
+
+ animator.setDuration((long) (200 * mSpeedFactor));
+ return animator;
+ }
+
+ @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
+ @Override
+ public ObjectAnimator getInitalAnimator(Context context){
+
+ ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(new Object(),
+ PropertyValuesHolder.ofFloat("alpha", 0.5f, 1.f),
+ PropertyValuesHolder.ofFloat("rotation", 60.f, 0.f));
+
+ animator.setDuration((long) (200 * mSpeedFactor));
+ return animator;
+ }
+
+ @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+ @Override
+ public ObjectAnimator getSwipeInAnimator(View view, float deltaX, float deltaY){
+
+ float deltaXAbs = Math.abs(deltaX);
+
+ float fractionCovered = 1.f - (deltaXAbs / view.getWidth());
+ long duration = Math.abs((int) ((1 - fractionCovered) * 200 * mSpeedFactor));
+
+ // Animate position and alpha of swiped item
+
+ ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view,
+ PropertyValuesHolder.ofFloat("alpha", 1.f),
+ PropertyValuesHolder.ofFloat("translationX", 0.f),
+ PropertyValuesHolder.ofFloat("rotationY", 0.f));
+
+ animator.setDuration(duration).setInterpolator(new BounceInterpolator());
+
+ return animator;
+ }
+
+ @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+ @Override
+ public ObjectAnimator getSwipeOutAnimator(View view, float deltaX, float deltaY){
+
+ float endX;
+ float endRotationY;
+
+ float deltaXAbs = Math.abs(deltaX);
+
+ float fractionCovered = 1.f - (deltaXAbs / view.getWidth());
+ long duration = Math.abs((int) ((1 - fractionCovered) * 200 * mSpeedFactor));
+
+ endX = deltaX < 0 ? -view.getWidth() : view.getWidth();
+ if (deltaX > 0)
+ endRotationY = -15.f;
+ else
+ endRotationY = 15.f;
+
+ // Animate position and alpha of swiped item
+ return ObjectAnimator.ofPropertyValuesHolder(view,
+ PropertyValuesHolder.ofFloat("alpha", 0.f),
+ PropertyValuesHolder.ofFloat("translationX", endX),
+ PropertyValuesHolder.ofFloat("rotationY", endRotationY)).setDuration(duration);
+
+ }
+
+}
diff --git a/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/MainActivity.java b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/MainActivity.java
new file mode 100644
index 000000000..bb1f9a168
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/MainActivity.java
@@ -0,0 +1,91 @@
+/*
+* Copyright 2013 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.example.android.batchstepsensor;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentTransaction;
+import android.view.Menu;
+
+import com.example.android.common.activities.SampleActivityBase;
+import com.example.android.common.logger.Log;
+
+public class MainActivity extends SampleActivityBase implements CardStream {
+ public static final String TAG = "MainActivity";
+ public static final String FRAGTAG = "BatchStepSensorFragment";
+
+ private CardStreamFragment mCardStreamFragment;
+
+ private StreamRetentionFragment mRetentionFragment;
+ private static final String RETENTION_TAG = "retention";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ FragmentManager fm = getSupportFragmentManager();
+ BatchStepSensorFragment fragment =
+ (BatchStepSensorFragment) fm.findFragmentByTag(FRAGTAG);
+
+ if (fragment == null) {
+ FragmentTransaction transaction = fm.beginTransaction();
+ fragment = new BatchStepSensorFragment();
+ transaction.add(fragment, FRAGTAG);
+ transaction.commit();
+ }
+
+ // Use fragment as click listener for cards, but must implement correct interface
+ if(!(fragment instanceof OnCardClickListener)){
+ throw new ClassCastException("BatchStepSensorFragment must " +
+ "implement OnCardClickListener interface.");
+ }
+ OnCardClickListener clickListener = (OnCardClickListener) fm.findFragmentByTag(FRAGTAG);
+
+ mRetentionFragment = (StreamRetentionFragment) fm.findFragmentByTag(RETENTION_TAG);
+ if (mRetentionFragment == null) {
+ mRetentionFragment = new StreamRetentionFragment();
+ fm.beginTransaction().add(mRetentionFragment, RETENTION_TAG).commit();
+ } else {
+ // If the retention fragment already existed, we need to pull some state.
+ // pull state out
+ CardStreamState state = mRetentionFragment.getCardStream();
+
+ // dump it in CardStreamFragment.
+ mCardStreamFragment =
+ (CardStreamFragment) fm.findFragmentById(R.id.fragment_cardstream);
+ mCardStreamFragment.restoreState(state, clickListener);
+ }
+ }
+
+ public CardStreamFragment getCardStream() {
+ if (mCardStreamFragment == null) {
+ mCardStreamFragment = (CardStreamFragment)
+ getSupportFragmentManager().findFragmentById(R.id.fragment_cardstream);
+ }
+ return mCardStreamFragment;
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ CardStreamState state = getCardStream().dumpState();
+ mRetentionFragment.storeCardStream(state);
+ }
+}
diff --git a/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/OnCardClickListener.java b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/OnCardClickListener.java
new file mode 100644
index 000000000..f02411057
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/OnCardClickListener.java
@@ -0,0 +1,24 @@
+/*
+* Copyright 2013 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.example.android.batchstepsensor;
+
+public interface OnCardClickListener {
+ public void onCardClick(int cardActionId, String cardTag);
+}
diff --git a/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/StreamRetentionFragment.java b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/StreamRetentionFragment.java
new file mode 100644
index 000000000..7cd7f2baa
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/StreamRetentionFragment.java
@@ -0,0 +1,41 @@
+/*
+* Copyright 2013 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.example.android.batchstepsensor;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+
+public class StreamRetentionFragment extends Fragment {
+
+ CardStreamState mState;
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ setRetainInstance(true);
+ }
+
+ public void storeCardStream(CardStreamState state) {
+ mState = state;
+ }
+
+ public CardStreamState getCardStream() {
+ return mState;
+ }
+}
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/activities/SampleActivityBase.java b/samples/browseable/BatchStepSensor/src/com.example.android.common/activities/SampleActivityBase.java
index 3228927b7..3228927b7 100644
--- a/samples/browseable/repeatingAlarm/src/com.example.android.common/activities/SampleActivityBase.java
+++ b/samples/browseable/BatchStepSensor/src/com.example.android.common/activities/SampleActivityBase.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/Log.java b/samples/browseable/BatchStepSensor/src/com.example.android.common/logger/Log.java
index 17503c568..17503c568 100644
--- a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/Log.java
+++ b/samples/browseable/BatchStepSensor/src/com.example.android.common/logger/Log.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/BatchStepSensor/src/com.example.android.common/logger/LogFragment.java
index b302acd4b..b302acd4b 100644
--- a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogFragment.java
+++ b/samples/browseable/BatchStepSensor/src/com.example.android.common/logger/LogFragment.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogNode.java b/samples/browseable/BatchStepSensor/src/com.example.android.common/logger/LogNode.java
index bc37cabc0..bc37cabc0 100644
--- a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogNode.java
+++ b/samples/browseable/BatchStepSensor/src/com.example.android.common/logger/LogNode.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogView.java b/samples/browseable/BatchStepSensor/src/com.example.android.common/logger/LogView.java
index c01542b91..c01542b91 100644
--- a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogView.java
+++ b/samples/browseable/BatchStepSensor/src/com.example.android.common/logger/LogView.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/BatchStepSensor/src/com.example.android.common/logger/LogWrapper.java
index 16a9e7ba2..16a9e7ba2 100644
--- a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogWrapper.java
+++ b/samples/browseable/BatchStepSensor/src/com.example.android.common/logger/LogWrapper.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/BatchStepSensor/src/com.example.android.common/logger/MessageOnlyLogFilter.java
index 19967dcd4..19967dcd4 100644
--- a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java
+++ b/samples/browseable/BatchStepSensor/src/com.example.android.common/logger/MessageOnlyLogFilter.java
diff --git a/samples/browseable/CustomChoiceList/res/values-sw600dp/dimens.xml b/samples/browseable/BluetoothLeGatt/res/values-sw600dp/template-dimens.xml
index 22074a2bd..22074a2bd 100644
--- a/samples/browseable/CustomChoiceList/res/values-sw600dp/dimens.xml
+++ b/samples/browseable/BluetoothLeGatt/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/CustomChoiceList/res/values-sw600dp/styles.xml b/samples/browseable/BluetoothLeGatt/res/values-sw600dp/template-styles.xml
index 03d197418..03d197418 100644
--- a/samples/browseable/CustomChoiceList/res/values-sw600dp/styles.xml
+++ b/samples/browseable/BluetoothLeGatt/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/StorageClient/res/values/dimens.xml b/samples/browseable/BluetoothLeGatt/res/values/template-dimens.xml
index 39e710b5c..39e710b5c 100644
--- a/samples/browseable/StorageClient/res/values/dimens.xml
+++ b/samples/browseable/BluetoothLeGatt/res/values/template-dimens.xml
diff --git a/samples/browseable/BluetoothLeGatt/res/values/template-styles.xml b/samples/browseable/BluetoothLeGatt/res/values/template-styles.xml
new file mode 100644
index 000000000..404623e3d
--- /dev/null
+++ b/samples/browseable/BluetoothLeGatt/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/CustomNotifications/res/values-sw600dp/dimens.xml b/samples/browseable/BorderlessButtons/res/values-sw600dp/template-dimens.xml
index 22074a2bd..22074a2bd 100644
--- a/samples/browseable/CustomNotifications/res/values-sw600dp/dimens.xml
+++ b/samples/browseable/BorderlessButtons/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/CustomNotifications/res/values-sw600dp/styles.xml b/samples/browseable/BorderlessButtons/res/values-sw600dp/template-styles.xml
index 03d197418..03d197418 100644
--- a/samples/browseable/CustomNotifications/res/values-sw600dp/styles.xml
+++ b/samples/browseable/BorderlessButtons/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/BorderlessButtons/res/values/dimens.xml b/samples/browseable/BorderlessButtons/res/values/dimens.xml
index 39e710b5c..71a1fc7cf 100644
--- a/samples/browseable/BorderlessButtons/res/values/dimens.xml
+++ b/samples/browseable/BorderlessButtons/res/values/dimens.xml
@@ -16,17 +16,10 @@
<resources>
- <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+ <dimen name="standard_touch_target_size">48dp</dimen>
- <dimen name="margin_tiny">4dp</dimen>
- <dimen name="margin_small">8dp</dimen>
- <dimen name="margin_medium">16dp</dimen>
- <dimen name="margin_large">32dp</dimen>
- <dimen name="margin_huge">64dp</dimen>
+ <!-- Meta-dimension that switches on screen size -->
- <!-- Semantic definitions -->
-
- <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
- <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="page_margin">@dimen/margin_medium</dimen>
</resources>
diff --git a/samples/browseable/BorderlessButtons/res/values/styles.xml b/samples/browseable/BorderlessButtons/res/values/styles.xml
index 404623e3d..36e0445dd 100644
--- a/samples/browseable/BorderlessButtons/res/values/styles.xml
+++ b/samples/browseable/BorderlessButtons/res/values/styles.xml
@@ -16,27 +16,16 @@
<resources>
- <!-- Activity themes -->
-
- <style name="Theme.Base" parent="android:Theme.Holo.Light" />
-
- <style name="Theme.Sample" parent="Theme.Base" />
-
- <style name="AppTheme" parent="Theme.Sample" />
<!-- Widget styling -->
- <style name="Widget" />
-
- <style name="Widget.SampleMessage">
+ <style name="Widget.DescriptionBar">
+ <item name="android:background">#fb3</item>
+ <item name="android:paddingTop">@dimen/margin_medium</item>
+ <item name="android:paddingBottom">@dimen/margin_medium</item>
+ <item name="android:paddingLeft">@dimen/page_margin</item>
+ <item name="android:paddingRight">@dimen/page_margin</item>
<item name="android:textAppearance">?android:textAppearanceMedium</item>
<item name="android:lineSpacingMultiplier">1.1</item>
</style>
- <style name="Widget.SampleMessageTile">
- <item name="android:background">@drawable/tile</item>
- <item name="android:shadowColor">#7F000000</item>
- <item name="android:shadowDy">-3.5</item>
- <item name="android:shadowRadius">2</item>
- </style>
-
</resources>
diff --git a/samples/browseable/repeatingAlarm/res/values/dimens.xml b/samples/browseable/BorderlessButtons/res/values/template-dimens.xml
index 39e710b5c..39e710b5c 100644
--- a/samples/browseable/repeatingAlarm/res/values/dimens.xml
+++ b/samples/browseable/BorderlessButtons/res/values/template-dimens.xml
diff --git a/samples/browseable/BorderlessButtons/res/values/template-styles.xml b/samples/browseable/BorderlessButtons/res/values/template-styles.xml
new file mode 100644
index 000000000..404623e3d
--- /dev/null
+++ b/samples/browseable/BorderlessButtons/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/CardEmulation/AndroidManifest.xml b/samples/browseable/CardEmulation/AndroidManifest.xml
new file mode 100644
index 000000000..4a4af0882
--- /dev/null
+++ b/samples/browseable/CardEmulation/AndroidManifest.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.cardemulation"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <!-- Card emulation was introduced in API 19. -->
+ <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19" />
+ <uses-feature android:name="android.hardware.nfc.hce" android:required="true" />
+ <uses-permission android:name="android.permission.NFC" />
+
+ <application android:allowBackup="true"
+ android:label="@string/app_name"
+ android:icon="@drawable/ic_launcher"
+ android:theme="@style/AppTheme">
+
+ <!-- Basic UI for sample discoverability. -->
+ <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>
+
+ <!-- BEGIN_INCLUDE(CardEmulationManifest) -->
+ <!-- Service for handling communication with NFC terminal. -->
+ <service android:name=".CardService"
+ android:exported="true"
+ android:permission="android.permission.BIND_NFC_SERVICE">
+ <!-- Intent filter indicating that we support card emulation. -->
+ <intent-filter>
+ <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ </intent-filter>
+ <!-- Required XML configuration file, listing the AIDs that we are emulating cards
+ for. This defines what protocols our card emulation service supports. -->
+ <meta-data android:name="android.nfc.cardemulation.host_apdu_service"
+ android:resource="@xml/aid_list"/>
+ </service>
+ <!-- END_INCLUDE(CardEmulationManifest) -->
+ </application>
+
+
+</manifest>
diff --git a/samples/browseable/CardEmulation/_index.jd b/samples/browseable/CardEmulation/_index.jd
new file mode 100644
index 000000000..92a1f630d
--- /dev/null
+++ b/samples/browseable/CardEmulation/_index.jd
@@ -0,0 +1,17 @@
+
+
+
+page.tags="CardEmulation"
+sample.group=Connectivity
+@jd:body
+
+<p>
+
+ This sample demonstrates how to emulate an NFC card, using the "host card emulation"
+ feature added in Android 4.4. This sample makes the device appear as a loyalty card
+ whenever the screen is on and the user taps their device on an appropriately configured
+ NFC reader.
+
+ The "CardReader" sample can be used to read the loyalty card implemented in this sample.
+
+ </p>
diff --git a/samples/browseable/CardEmulation/res/drawable-hdpi/ic_launcher.png b/samples/browseable/CardEmulation/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 000000000..0be8f85e2
--- /dev/null
+++ b/samples/browseable/CardEmulation/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CardEmulation/res/drawable-hdpi/tile.9.png b/samples/browseable/CardEmulation/res/drawable-hdpi/tile.9.png
new file mode 100644
index 000000000..135862883
--- /dev/null
+++ b/samples/browseable/CardEmulation/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/CardEmulation/res/drawable-mdpi/ic_launcher.png b/samples/browseable/CardEmulation/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 000000000..eb13405ad
--- /dev/null
+++ b/samples/browseable/CardEmulation/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CardEmulation/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/CardEmulation/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..8d1e6a6af
--- /dev/null
+++ b/samples/browseable/CardEmulation/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CardEmulation/res/drawable-xxhdpi/card_background.png b/samples/browseable/CardEmulation/res/drawable-xxhdpi/card_background.png
new file mode 100644
index 000000000..86a7ba764
--- /dev/null
+++ b/samples/browseable/CardEmulation/res/drawable-xxhdpi/card_background.png
Binary files differ
diff --git a/samples/browseable/CardEmulation/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/CardEmulation/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..7ea109fce
--- /dev/null
+++ b/samples/browseable/CardEmulation/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CardEmulation/res/layout-w720dp/activity_main.xml b/samples/browseable/CardEmulation/res/layout-w720dp/activity_main.xml
new file mode 100755
index 000000000..c9a52f621
--- /dev/null
+++ b/samples/browseable/CardEmulation/res/layout-w720dp/activity_main.xml
@@ -0,0 +1,73 @@
+<!--
+ Copyright 2013 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.
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/sample_main_layout">
+
+ <LinearLayout
+ android:id="@+id/sample_output"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:orientation="vertical">
+
+ <FrameLayout
+ style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/margin_medium"
+ android:paddingRight="@dimen/margin_medium"
+ android:paddingTop="@dimen/margin_large"
+ android:paddingBottom="@dimen/margin_large"
+ android:text="@string/intro_message" />
+ </FrameLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@android:color/darker_gray" />
+
+ <fragment
+ android:name="com.example.android.common.logger.LogFragment"
+ android:id="@+id/log_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1" />
+
+ </LinearLayout>
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:background="@android:color/darker_gray" />
+
+ <FrameLayout
+ android:id="@+id/sample_content_fragment"
+ android:layout_weight="2"
+ android:layout_width="0px"
+ android:layout_height="match_parent" />
+
+</LinearLayout>
+
+
diff --git a/samples/browseable/CardEmulation/res/layout/activity_main.xml b/samples/browseable/CardEmulation/res/layout/activity_main.xml
new file mode 100755
index 000000000..1ae4f981e
--- /dev/null
+++ b/samples/browseable/CardEmulation/res/layout/activity_main.xml
@@ -0,0 +1,65 @@
+<!--
+ Copyright 2013 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.
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/sample_main_layout">
+
+ <ViewAnimator
+ android:id="@+id/sample_output"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1">
+
+ <ScrollView
+ style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/horizontal_page_margin"
+ android:paddingRight="@dimen/horizontal_page_margin"
+ android:paddingTop="@dimen/vertical_page_margin"
+ android:paddingBottom="@dimen/vertical_page_margin"
+ android:text="@string/intro_message" />
+ </ScrollView>
+
+ <fragment
+ android:name="com.example.android.common.logger.LogFragment"
+ android:id="@+id/log_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ </ViewAnimator>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@android:color/darker_gray" />
+
+ <FrameLayout
+ android:id="@+id/sample_content_fragment"
+ android:layout_weight="2"
+ android:layout_width="match_parent"
+ android:layout_height="0px" />
+
+</LinearLayout>
+
diff --git a/samples/browseable/CardEmulation/res/layout/main_fragment.xml b/samples/browseable/CardEmulation/res/layout/main_fragment.xml
new file mode 100644
index 000000000..2c69743e2
--- /dev/null
+++ b/samples/browseable/CardEmulation/res/layout/main_fragment.xml
@@ -0,0 +1,65 @@
+<!--
+Copyright (C) 2013 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.
+-->
+
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="380dp"
+ android:layout_height="242.25dp"
+ android:layout_gravity="center"
+ android:layout_margin="20dp">
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:src="@drawable/card_background"
+ />
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:padding="20dp"
+ android:layout_gravity="center"
+ android:clickable="true">
+ <TextView
+ android:id="@+id/card_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/card_title"
+ android:fontFamily="sans-serif-condensed"
+ android:textStyle="bold"
+ android:textSize="32dp"
+ />
+ <TextView
+ android:id="@+id/card_account_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/account_number"
+ android:fontFamily="sans-serif"
+ android:textStyle="bold"
+ android:textSize="18dp"
+ android:layout_marginTop="40dp"
+ />
+ <EditText
+ android:id="@+id/card_account_field"
+ android:width="360dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:fontFamily="sans-serif-condensed"
+ android:textStyle="bold"
+ android:textSize="42dp"
+ android:singleLine="true"
+ android:inputType="number" />
+ </LinearLayout>
+</FrameLayout> \ No newline at end of file
diff --git a/samples/browseable/CardEmulation/res/menu/main.xml b/samples/browseable/CardEmulation/res/menu/main.xml
new file mode 100644
index 000000000..b49c2c526
--- /dev/null
+++ b/samples/browseable/CardEmulation/res/menu/main.xml
@@ -0,0 +1,21 @@
+<!--
+ Copyright 2013 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.
+ -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/menu_toggle_log"
+ android:showAsAction="always"
+ android:title="@string/sample_show_log" />
+</menu>
diff --git a/samples/browseable/DoneBar/res/values-sw600dp/dimens.xml b/samples/browseable/CardEmulation/res/values-sw600dp/template-dimens.xml
index 22074a2bd..22074a2bd 100644
--- a/samples/browseable/DoneBar/res/values-sw600dp/dimens.xml
+++ b/samples/browseable/CardEmulation/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/DoneBar/res/values-sw600dp/styles.xml b/samples/browseable/CardEmulation/res/values-sw600dp/template-styles.xml
index 03d197418..03d197418 100644
--- a/samples/browseable/DoneBar/res/values-sw600dp/styles.xml
+++ b/samples/browseable/CardEmulation/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/CardEmulation/res/values/base-strings.xml b/samples/browseable/CardEmulation/res/values/base-strings.xml
new file mode 100644
index 000000000..9062a239a
--- /dev/null
+++ b/samples/browseable/CardEmulation/res/values/base-strings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+ <string name="app_name">CardEmulation</string>
+ <string name="intro_message">
+ <![CDATA[
+
+
+ This sample demonstrates how to emulate an NFC card, using the "host card emulation"
+ feature added in Android 4.4. This sample makes the device appear as a loyalty card
+ whenever the screen is on and the user taps their device on an appropriately configured
+ NFC reader.
+
+ The "CardReader" sample can be used to read the loyalty card implemented in this sample.
+
+
+ ]]>
+ </string>
+</resources>
diff --git a/samples/browseable/CardEmulation/res/values/strings.xml b/samples/browseable/CardEmulation/res/values/strings.xml
new file mode 100755
index 000000000..7b9d9ec4f
--- /dev/null
+++ b/samples/browseable/CardEmulation/res/values/strings.xml
@@ -0,0 +1,19 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="sample_show_log">Show Log</string>
+ <string name="sample_hide_log">Hide Log</string>
+</resources>
diff --git a/samples/browseable/CardEmulation/res/values/template-dimens.xml b/samples/browseable/CardEmulation/res/values/template-dimens.xml
new file mode 100644
index 000000000..39e710b5c
--- /dev/null
+++ b/samples/browseable/CardEmulation/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/CardEmulation/res/values/template-styles.xml b/samples/browseable/CardEmulation/res/values/template-styles.xml
new file mode 100644
index 000000000..404623e3d
--- /dev/null
+++ b/samples/browseable/CardEmulation/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/CardEmulation/res/xml/aid_list.xml b/samples/browseable/CardEmulation/res/xml/aid_list.xml
new file mode 100644
index 000000000..15ed7549a
--- /dev/null
+++ b/samples/browseable/CardEmulation/res/xml/aid_list.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2013 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.
+-->
+
+<!-- This file defines which AIDs this application should emulate cards for.
+
+ Vendor-specific AIDs should always start with an "F", according to the ISO 7816 spec. We
+ recommended vendor-specific AIDs be at least 6 characters long, to provide sufficient
+ uniqueness. Note, however, that longer AIDs may impose a burden on non-Android NFC terminals.
+ AIDs may not exceed 32 characters (16 bytes).
+
+ Additionally, AIDs must always contain an even number of characters, in hexadecimal format.
+
+ In order to avoid prompting the user to select which service they want to use when the device
+ is scanned, this app must be selected as the default handler for an AID group by the user, or
+ the terminal must select *all* AIDs defined in the category simultaneously ("exact match").
+-->
+<!-- BEGIN_INCLUDE(CardEmulationXML) -->
+<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
+ android:description="@string/service_name"
+ android:requireDeviceUnlock="false">
+ <!--
+ If category="payment" is used for any aid-groups, you must also add an android:apduServiceBanner
+ attribute above, like so:
+
+ android:apduServiceBanner="@drawable/settings_banner"
+
+ apduServiceBanner should be 260x96 dp. In pixels, that works out to...
+ - drawable-xxhdpi: 780x288 px
+ - drawable-xhdpi: 520x192 px
+ - drawable-hdpi: 390x144 px
+ - drawable-mdpi: 260x96 px
+
+ The apduServiceBanner is displayed in the "Tap & Pay" menu in the system Settings app, and
+ is only displayed for apps which implement the "payment" AID category.
+
+ Since this sample is implementing a non-standard card type (a loyalty card, specifically), we
+ do not need to define a banner.
+
+ Important: category="payment" should only be used for industry-standard payment cards. If you are
+ implementing a closed-loop payment system (e.g. stored value cards for a specific merchant
+ or transit system), use category="other". This is because only one "payment" card may be
+ active at a time, whereas all "other" cards are active simultaneously (subject to AID
+ dispatch).
+ -->
+
+ <aid-group android:description="@string/card_title" android:category="other">
+ <aid-filter android:name="F222222222"/>
+ </aid-group>
+<!-- END_INCLUDE(CardEmulationXML) -->
+</host-apdu-service>
diff --git a/samples/browseable/CardEmulation/src/com.example.android.cardemulation/AccountStorage.java b/samples/browseable/CardEmulation/src/com.example.android.cardemulation/AccountStorage.java
new file mode 100644
index 000000000..e02d480c9
--- /dev/null
+++ b/samples/browseable/CardEmulation/src/com.example.android.cardemulation/AccountStorage.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2013 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.example.android.cardemulation;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+/**
+ * Utility class for persisting account numbers to disk.
+ *
+ * <p>The default SharedPreferences instance is used as the backing storage. Values are cached
+ * in memory for performance.
+ *
+ * <p>This class is thread-safe.
+ */
+public class AccountStorage {
+ private static final String PREF_ACCOUNT_NUMBER = "account_number";
+ private static final String DEFAULT_ACCOUNT_NUMBER = "00000000";
+ private static final String TAG = "AccountStorage";
+ private static String sAccount = null;
+ private static final Object sAccountLock = new Object();
+
+ public static void SetAccount(Context c, String s) {
+ synchronized(sAccountLock) {
+ Log.i(TAG, "Setting account number: " + s);
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c);
+ prefs.edit().putString(PREF_ACCOUNT_NUMBER, s).commit();
+ sAccount = s;
+ }
+ }
+
+ public static String GetAccount(Context c) {
+ synchronized (sAccountLock) {
+ if (sAccount == null) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c);
+ String account = prefs.getString(PREF_ACCOUNT_NUMBER, DEFAULT_ACCOUNT_NUMBER);
+ sAccount = account;
+ }
+ return sAccount;
+ }
+ }
+}
diff --git a/samples/browseable/CardEmulation/src/com.example.android.cardemulation/CardEmulationFragment.java b/samples/browseable/CardEmulation/src/com.example.android.cardemulation/CardEmulationFragment.java
new file mode 100644
index 000000000..f26efda26
--- /dev/null
+++ b/samples/browseable/CardEmulation/src/com.example.android.cardemulation/CardEmulationFragment.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2013 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.example.android.cardemulation;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.EditText;
+
+/**
+ * Generic UI for sample discovery.
+ */
+public class CardEmulationFragment extends Fragment {
+
+ public static final String TAG = "CardEmulationFragment";
+
+ /** Called when sample is created. Displays generic UI with welcome text. */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ View v = inflater.inflate(R.layout.main_fragment, container, false);
+ EditText account = (EditText) v.findViewById(R.id.card_account_field);
+ account.setText(AccountStorage.GetAccount(getActivity()));
+ account.addTextChangedListener(new AccountUpdater());
+ return v;
+ }
+
+
+ private class AccountUpdater implements TextWatcher {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ // Not implemented.
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ // Not implemented.
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ String account = s.toString();
+ AccountStorage.SetAccount(getActivity(), account);
+ }
+ }
+}
diff --git a/samples/browseable/CardEmulation/src/com.example.android.cardemulation/CardService.java b/samples/browseable/CardEmulation/src/com.example.android.cardemulation/CardService.java
new file mode 100644
index 000000000..a409d28f4
--- /dev/null
+++ b/samples/browseable/CardEmulation/src/com.example.android.cardemulation/CardService.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2013 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.example.android.cardemulation;
+
+import android.nfc.cardemulation.HostApduService;
+import android.os.Bundle;
+import com.example.android.common.logger.Log;
+
+import java.util.Arrays;
+
+/**
+ * This is a sample APDU Service which demonstrates how to interface with the card emulation support
+ * added in Android 4.4, KitKat.
+ *
+ * <p>This sample replies to any requests sent with the string "Hello World". In real-world
+ * situations, you would need to modify this code to implement your desired communication
+ * protocol.
+ *
+ * <p>This sample will be invoked for any terminals selecting AIDs of 0xF11111111, 0xF22222222, or
+ * 0xF33333333. See src/main/res/xml/aid_list.xml for more details.
+ *
+ * <p class="note">Note: This is a low-level interface. Unlike the NdefMessage many developers
+ * are familiar with for implementing Android Beam in apps, card emulation only provides a
+ * byte-array based communication channel. It is left to developers to implement higher level
+ * protocol support as needed.
+ */
+public class CardService extends HostApduService {
+ private static final String TAG = "CardService";
+ // AID for our loyalty card service.
+ private static final String SAMPLE_LOYALTY_CARD_AID = "F222222222";
+ // ISO-DEP command HEADER for selecting an AID.
+ // Format: [Class | Instruction | Parameter 1 | Parameter 2]
+ private static final String SELECT_APDU_HEADER = "00A40400";
+ // "OK" status word sent in response to SELECT AID command (0x9000)
+ private static final byte[] SELECT_OK_SW = HexStringToByteArray("9000");
+ // "UNKNOWN" status word sent in response to invalid APDU command (0x0000)
+ private static final byte[] UNKNOWN_CMD_SW = HexStringToByteArray("0000");
+ private static final byte[] SELECT_APDU = BuildSelectApdu(SAMPLE_LOYALTY_CARD_AID);
+
+ /**
+ * Called if the connection to the NFC card is lost, in order to let the application know the
+ * cause for the disconnection (either a lost link, or another AID being selected by the
+ * reader).
+ *
+ * @param reason Either DEACTIVATION_LINK_LOSS or DEACTIVATION_DESELECTED
+ */
+ @Override
+ public void onDeactivated(int reason) { }
+
+ /**
+ * This method will be called when a command APDU has been received from a remote device. A
+ * response APDU can be provided directly by returning a byte-array in this method. In general
+ * response APDUs must be sent as quickly as possible, given the fact that the user is likely
+ * holding his device over an NFC reader when this method is called.
+ *
+ * <p class="note">If there are multiple services that have registered for the same AIDs in
+ * their meta-data entry, you will only get called if the user has explicitly selected your
+ * service, either as a default or just for the next tap.
+ *
+ * <p class="note">This method is running on the main thread of your application. If you
+ * cannot return a response APDU immediately, return null and use the {@link
+ * #sendResponseApdu(byte[])} method later.
+ *
+ * @param commandApdu The APDU that received from the remote device
+ * @param extras A bundle containing extra data. May be null.
+ * @return a byte-array containing the response APDU, or null if no response APDU can be sent
+ * at this point.
+ */
+ // BEGIN_INCLUDE(processCommandApdu)
+ @Override
+ public byte[] processCommandApdu(byte[] commandApdu, Bundle extras) {
+ Log.i(TAG, "Received APDU: " + ByteArrayToHexString(commandApdu));
+ // If the APDU matches the SELECT AID command for this service,
+ // send the loyalty card account number, followed by a SELECT_OK status trailer (0x9000).
+ if (Arrays.equals(SELECT_APDU, commandApdu)) {
+ String account = AccountStorage.GetAccount(this);
+ byte[] accountBytes = account.getBytes();
+ Log.i(TAG, "Sending account number: " + account);
+ return ConcatArrays(accountBytes, SELECT_OK_SW);
+ } else {
+ return UNKNOWN_CMD_SW;
+ }
+ }
+ // END_INCLUDE(processCommandApdu)
+
+ /**
+ * Build APDU for SELECT AID command. This command indicates which service a reader is
+ * interested in communicating with. See ISO 7816-4.
+ *
+ * @param aid Application ID (AID) to select
+ * @return APDU for SELECT AID command
+ */
+ public static byte[] BuildSelectApdu(String aid) {
+ // Format: [CLASS | INSTRUCTION | PARAMETER 1 | PARAMETER 2 | LENGTH | DATA]
+ return HexStringToByteArray(SELECT_APDU_HEADER + String.format("%02X",
+ aid.length() / 2) + aid);
+ }
+
+ /**
+ * Utility method to convert a byte array to a hexadecimal string.
+ *
+ * @param bytes Bytes to convert
+ * @return String, containing hexadecimal representation.
+ */
+ public static String ByteArrayToHexString(byte[] bytes) {
+ final char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+ char[] hexChars = new char[bytes.length * 2]; // Each byte has two hex characters (nibbles)
+ int v;
+ for (int j = 0; j < bytes.length; j++) {
+ v = bytes[j] & 0xFF; // Cast bytes[j] to int, treating as unsigned value
+ hexChars[j * 2] = hexArray[v >>> 4]; // Select hex character from upper nibble
+ hexChars[j * 2 + 1] = hexArray[v & 0x0F]; // Select hex character from lower nibble
+ }
+ return new String(hexChars);
+ }
+
+ /**
+ * Utility method to convert a hexadecimal string to a byte string.
+ *
+ * <p>Behavior with input strings containing non-hexadecimal characters is undefined.
+ *
+ * @param s String containing hexadecimal characters to convert
+ * @return Byte array generated from input
+ * @throws java.lang.IllegalArgumentException if input length is incorrect
+ */
+ public static byte[] HexStringToByteArray(String s) throws IllegalArgumentException {
+ int len = s.length();
+ if (len % 2 == 1) {
+ throw new IllegalArgumentException("Hex string must have even number of characters");
+ }
+ byte[] data = new byte[len / 2]; // Allocate 1 byte per 2 hex characters
+ for (int i = 0; i < len; i += 2) {
+ // Convert each character into a integer (base-16), then bit-shift into place
+ data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ + Character.digit(s.charAt(i+1), 16));
+ }
+ return data;
+ }
+
+ /**
+ * Utility method to concatenate two byte arrays.
+ * @param first First array
+ * @param rest Any remaining arrays
+ * @return Concatenated copy of input arrays
+ */
+ public static byte[] ConcatArrays(byte[] first, byte[]... rest) {
+ int totalLength = first.length;
+ for (byte[] array : rest) {
+ totalLength += array.length;
+ }
+ byte[] result = Arrays.copyOf(first, totalLength);
+ int offset = first.length;
+ for (byte[] array : rest) {
+ System.arraycopy(array, 0, result, offset, array.length);
+ offset += array.length;
+ }
+ return result;
+ }
+}
diff --git a/samples/browseable/CardEmulation/src/com.example.android.cardemulation/MainActivity.java b/samples/browseable/CardEmulation/src/com.example.android.cardemulation/MainActivity.java
new file mode 100644
index 000000000..0515609d0
--- /dev/null
+++ b/samples/browseable/CardEmulation/src/com.example.android.cardemulation/MainActivity.java
@@ -0,0 +1,110 @@
+/*
+* Copyright 2013 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.example.android.cardemulation;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.ViewAnimator;
+
+import com.example.android.common.activities.SampleActivityBase;
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogFragment;
+import com.example.android.common.logger.LogWrapper;
+import com.example.android.common.logger.MessageOnlyLogFilter;
+
+/**
+ * A simple launcher activity containing a summary sample description, sample log and a custom
+ * {@link android.support.v4.app.Fragment} which can display a view.
+ * <p>
+ * For devices with displays with a width of 720dp or greater, the sample log is always visible,
+ * on other devices it's visibility is controlled by an item on the Action Bar.
+ */
+public class MainActivity extends SampleActivityBase {
+
+ public static final String TAG = "MainActivity";
+
+ // Whether the Log Fragment is currently shown
+ private boolean mLogShown;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+ CardEmulationFragment fragment = new CardEmulationFragment();
+ transaction.replace(R.id.sample_content_fragment, fragment);
+ transaction.commit();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.main, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ MenuItem logToggle = menu.findItem(R.id.menu_toggle_log);
+ logToggle.setVisible(findViewById(R.id.sample_output) instanceof ViewAnimator);
+ logToggle.setTitle(mLogShown ? R.string.sample_hide_log : R.string.sample_show_log);
+
+ return super.onPrepareOptionsMenu(menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch(item.getItemId()) {
+ case R.id.menu_toggle_log:
+ mLogShown = !mLogShown;
+ ViewAnimator output = (ViewAnimator) findViewById(R.id.sample_output);
+ if (mLogShown) {
+ output.setDisplayedChild(1);
+ } else {
+ output.setDisplayedChild(0);
+ }
+ supportInvalidateOptionsMenu();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ /** Create a chain of targets that will receive log data */
+ @Override
+ public void initializeLogging() {
+ // Wraps Android's native log framework.
+ LogWrapper logWrapper = new LogWrapper();
+ // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+ Log.setLogNode(logWrapper);
+
+ // Filter strips out everything except the message text.
+ MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
+ logWrapper.setNext(msgFilter);
+
+ // On screen logging via a fragment with a TextView.
+ LogFragment logFragment = (LogFragment) getSupportFragmentManager()
+ .findFragmentById(R.id.log_fragment);
+ msgFilter.setNext(logFragment.getLogView());
+
+ Log.i(TAG, "Ready");
+ }
+}
diff --git a/samples/browseable/CardEmulation/src/com.example.android.common/activities/SampleActivityBase.java b/samples/browseable/CardEmulation/src/com.example.android.common/activities/SampleActivityBase.java
new file mode 100644
index 000000000..3228927b7
--- /dev/null
+++ b/samples/browseable/CardEmulation/src/com.example.android.common/activities/SampleActivityBase.java
@@ -0,0 +1,52 @@
+/*
+* Copyright 2013 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.example.android.common.activities;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogWrapper;
+
+/**
+ * Base launcher activity, to handle most of the common plumbing for samples.
+ */
+public class SampleActivityBase extends FragmentActivity {
+
+ public static final String TAG = "SampleActivityBase";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ initializeLogging();
+ }
+
+ /** Set up targets to receive log data */
+ public void initializeLogging() {
+ // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+ // Wraps Android's native log framework
+ LogWrapper logWrapper = new LogWrapper();
+ Log.setLogNode(logWrapper);
+
+ Log.i(TAG, "Ready");
+ }
+}
diff --git a/samples/browseable/CardEmulation/src/com.example.android.common/logger/Log.java b/samples/browseable/CardEmulation/src/com.example.android.common/logger/Log.java
new file mode 100644
index 000000000..17503c568
--- /dev/null
+++ b/samples/browseable/CardEmulation/src/com.example.android.common/logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 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.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+ // Grabbing the native values from Android's native logging facilities,
+ // to make for easy migration and interop.
+ public static final int NONE = -1;
+ public static final int VERBOSE = android.util.Log.VERBOSE;
+ public static final int DEBUG = android.util.Log.DEBUG;
+ public static final int INFO = android.util.Log.INFO;
+ public static final int WARN = android.util.Log.WARN;
+ public static final int ERROR = android.util.Log.ERROR;
+ public static final int ASSERT = android.util.Log.ASSERT;
+
+ // Stores the beginning of the LogNode topology.
+ private static LogNode mLogNode;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public static LogNode getLogNode() {
+ return mLogNode;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to.
+ */
+ public static void setLogNode(LogNode node) {
+ mLogNode = node;
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void println(int priority, String tag, String msg, Throwable tr) {
+ if (mLogNode != null) {
+ mLogNode.println(priority, tag, msg, tr);
+ }
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ */
+ public static void println(int priority, String tag, String msg) {
+ println(priority, tag, msg, null);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void v(String tag, String msg, Throwable tr) {
+ println(VERBOSE, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void v(String tag, String msg) {
+ v(tag, msg, null);
+ }
+
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void d(String tag, String msg, Throwable tr) {
+ println(DEBUG, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void d(String tag, String msg) {
+ d(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void i(String tag, String msg, Throwable tr) {
+ println(INFO, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void i(String tag, String msg) {
+ i(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, String msg, Throwable tr) {
+ println(WARN, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void w(String tag, String msg) {
+ w(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, Throwable tr) {
+ w(tag, null, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void e(String tag, String msg, Throwable tr) {
+ println(ERROR, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void e(String tag, String msg) {
+ e(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, String msg, Throwable tr) {
+ println(ASSERT, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void wtf(String tag, String msg) {
+ wtf(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, Throwable tr) {
+ wtf(tag, null, tr);
+ }
+}
diff --git a/samples/browseable/CardEmulation/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/CardEmulation/src/com.example.android.common/logger/LogFragment.java
new file mode 100644
index 000000000..b302acd4b
--- /dev/null
+++ b/samples/browseable/CardEmulation/src/com.example.android.common/logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 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.
+*/
+/*
+ * Copyright 2013 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.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+ private LogView mLogView;
+ private ScrollView mScrollView;
+
+ public LogFragment() {}
+
+ public View inflateViews() {
+ mScrollView = new ScrollView(getActivity());
+ ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT);
+ mScrollView.setLayoutParams(scrollParams);
+
+ mLogView = new LogView(getActivity());
+ ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+ logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+ mLogView.setLayoutParams(logParams);
+ mLogView.setClickable(true);
+ mLogView.setFocusable(true);
+ mLogView.setTypeface(Typeface.MONOSPACE);
+
+ // Want to set padding as 16 dips, setPadding takes pixels. Hooray math!
+ int paddingDips = 16;
+ double scale = getResources().getDisplayMetrics().density;
+ int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+ mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+ mLogView.setCompoundDrawablePadding(paddingPixels);
+
+ mLogView.setGravity(Gravity.BOTTOM);
+ mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+ mScrollView.addView(mLogView);
+ return mScrollView;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+
+ View result = inflateViews();
+
+ mLogView.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+ }
+ });
+ return result;
+ }
+
+ public LogView getLogView() {
+ return mLogView;
+ }
+} \ No newline at end of file
diff --git a/samples/browseable/CardEmulation/src/com.example.android.common/logger/LogNode.java b/samples/browseable/CardEmulation/src/com.example.android.common/logger/LogNode.java
new file mode 100644
index 000000000..bc37cabc0
--- /dev/null
+++ b/samples/browseable/CardEmulation/src/com.example.android.common/logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * 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.example.android.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+ /**
+ * Instructs first LogNode in the list to print the log data provided.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/CardEmulation/src/com.example.android.common/logger/LogView.java b/samples/browseable/CardEmulation/src/com.example.android.common/logger/LogView.java
new file mode 100644
index 000000000..c01542b91
--- /dev/null
+++ b/samples/browseable/CardEmulation/src/com.example.android.common/logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 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.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+ public LogView(Context context) {
+ super(context);
+ }
+
+ public LogView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public LogView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ /**
+ * Formats the log data and prints it out to the LogView.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+
+
+ String priorityStr = null;
+
+ // For the purposes of this View, we want to print the priority as readable text.
+ switch(priority) {
+ case android.util.Log.VERBOSE:
+ priorityStr = "VERBOSE";
+ break;
+ case android.util.Log.DEBUG:
+ priorityStr = "DEBUG";
+ break;
+ case android.util.Log.INFO:
+ priorityStr = "INFO";
+ break;
+ case android.util.Log.WARN:
+ priorityStr = "WARN";
+ break;
+ case android.util.Log.ERROR:
+ priorityStr = "ERROR";
+ break;
+ case android.util.Log.ASSERT:
+ priorityStr = "ASSERT";
+ break;
+ default:
+ break;
+ }
+
+ // Handily, the Log class has a facility for converting a stack trace into a usable string.
+ String exceptionStr = null;
+ if (tr != null) {
+ exceptionStr = android.util.Log.getStackTraceString(tr);
+ }
+
+ // Take the priority, tag, message, and exception, and concatenate as necessary
+ // into one usable line of text.
+ final StringBuilder outputBuilder = new StringBuilder();
+
+ String delimiter = "\t";
+ appendIfNotNull(outputBuilder, priorityStr, delimiter);
+ appendIfNotNull(outputBuilder, tag, delimiter);
+ appendIfNotNull(outputBuilder, msg, delimiter);
+ appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+ // In case this was originally called from an AsyncTask or some other off-UI thread,
+ // make sure the update occurs within the UI thread.
+ ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+ @Override
+ public void run() {
+ // Display the text we just generated within the LogView.
+ appendToLog(outputBuilder.toString());
+ }
+ })));
+
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+ * the logger takes so many arguments that might be null, this method helps cut out some of the
+ * agonizing tedium of writing the same 3 lines over and over.
+ * @param source StringBuilder containing the text to append to.
+ * @param addStr The String to append
+ * @param delimiter The String to separate the source and appended strings. A tab or comma,
+ * for instance.
+ * @return The fully concatenated String as a StringBuilder
+ */
+ private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+ if (addStr != null) {
+ if (addStr.length() == 0) {
+ delimiter = "";
+ }
+
+ return source.append(addStr).append(delimiter);
+ }
+ return source;
+ }
+
+ // The next LogNode in the chain.
+ LogNode mNext;
+
+ /** Outputs the string as a new line of log data in the LogView. */
+ public void appendToLog(String s) {
+ append("\n" + s);
+ }
+
+
+}
diff --git a/samples/browseable/CardEmulation/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/CardEmulation/src/com.example.android.common/logger/LogWrapper.java
new file mode 100644
index 000000000..16a9e7ba2
--- /dev/null
+++ b/samples/browseable/CardEmulation/src/com.example.android.common/logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * 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.example.android.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface. This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+ // For piping: The next node to receive Log data after this one has done its work.
+ private LogNode mNext;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /**
+ * Prints data out to the console using Android's native log mechanism.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ // There actually are log methods that don't take a msg parameter. For now,
+ // if that's the case, just convert null to the empty string and move on.
+ String useMsg = msg;
+ if (useMsg == null) {
+ useMsg = "";
+ }
+
+ // If an exeption was provided, convert that exception to a usable string and attach
+ // it to the end of the msg method.
+ if (tr != null) {
+ msg += "\n" + Log.getStackTraceString(tr);
+ }
+
+ // This is functionally identical to Log.x(tag, useMsg);
+ // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+ Log.println(priority, tag, useMsg);
+
+ // If this isn't the last node in the chain, move things along.
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+}
diff --git a/samples/browseable/CardEmulation/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/CardEmulation/src/com.example.android.common/logger/MessageOnlyLogFilter.java
new file mode 100644
index 000000000..19967dcd4
--- /dev/null
+++ b/samples/browseable/CardEmulation/src/com.example.android.common/logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 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.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+ LogNode mNext;
+
+ /**
+ * Takes the "next" LogNode as a parameter, to simplify chaining.
+ *
+ * @param next The next LogNode in the pipeline.
+ */
+ public MessageOnlyLogFilter(LogNode next) {
+ mNext = next;
+ }
+
+ public MessageOnlyLogFilter() {
+ }
+
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ if (mNext != null) {
+ getNext().println(Log.NONE, null, msg, null);
+ }
+ }
+
+ /**
+ * Returns the next LogNode in the chain.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+}
diff --git a/samples/browseable/CardReader/AndroidManifest.xml b/samples/browseable/CardReader/AndroidManifest.xml
new file mode 100644
index 000000000..a8ebd133a
--- /dev/null
+++ b/samples/browseable/CardReader/AndroidManifest.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.cardreader"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <!-- NFC Reader Mode was added in API 19. -->
+ <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19" />
+ <uses-permission android:name="android.permission.NFC" />
+ <uses-feature android:name="android.hardware.nfc" android:required="true" />
+
+ <application android:allowBackup="true"
+ android:label="@string/app_name"
+ android:icon="@drawable/ic_launcher"
+ android:theme="@style/AppTheme">
+ <activity android:name=".MainActivity"
+ android:label="@string/app_name"
+ android:launchMode="singleTop">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+
+ <!-- NFC-related intent filter. Allows application to handle messages from any
+ NFC-A devices discovered. Other Android devices are required to support NFC-A.
+ See: res/xml/nfc_tech_filter.xml -->
+ <intent-filter>
+ <action android:name="android.nfc.action.TECH_DISCOVERED" />
+ </intent-filter>
+ <meta-data
+ android:name="android.nfc.action.TECH_DISCOVERED"
+ android:resource="@xml/nfc_tech_filter" />
+ </activity>
+ </application>
+
+
+</manifest>
diff --git a/samples/browseable/CardReader/_index.jd b/samples/browseable/CardReader/_index.jd
new file mode 100644
index 000000000..72fba3d0c
--- /dev/null
+++ b/samples/browseable/CardReader/_index.jd
@@ -0,0 +1,17 @@
+
+
+
+page.tags="CardReader"
+sample.group=Connectivity
+@jd:body
+
+<p>
+
+ This sample demonstrates how to implement a low-level NFC card reader, for reading cards
+ that do not contain NDEF or Android Beam data. This sample is designed to read the virtual
+ loyalty card implemented in the "CardEmulation" sample.\n\n
+
+ In particular, this sample demonstrates how to disable Android Beam, select which AIDs the
+ reader is interested, and establish communication with the card
+
+ </p>
diff --git a/samples/browseable/CardReader/res/drawable-hdpi/ic_launcher.png b/samples/browseable/CardReader/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 000000000..9114e4428
--- /dev/null
+++ b/samples/browseable/CardReader/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CardReader/res/drawable-hdpi/tile.9.png b/samples/browseable/CardReader/res/drawable-hdpi/tile.9.png
new file mode 100644
index 000000000..135862883
--- /dev/null
+++ b/samples/browseable/CardReader/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/CardReader/res/drawable-mdpi/ic_launcher.png b/samples/browseable/CardReader/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 000000000..604fbd8d5
--- /dev/null
+++ b/samples/browseable/CardReader/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CardReader/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/CardReader/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..9e58d22db
--- /dev/null
+++ b/samples/browseable/CardReader/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CardReader/res/drawable-xxhdpi/card_background.png b/samples/browseable/CardReader/res/drawable-xxhdpi/card_background.png
new file mode 100644
index 000000000..86a7ba764
--- /dev/null
+++ b/samples/browseable/CardReader/res/drawable-xxhdpi/card_background.png
Binary files differ
diff --git a/samples/browseable/CardReader/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/CardReader/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..c550c0454
--- /dev/null
+++ b/samples/browseable/CardReader/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CardReader/res/layout-w720dp/activity_main.xml b/samples/browseable/CardReader/res/layout-w720dp/activity_main.xml
new file mode 100755
index 000000000..c9a52f621
--- /dev/null
+++ b/samples/browseable/CardReader/res/layout-w720dp/activity_main.xml
@@ -0,0 +1,73 @@
+<!--
+ Copyright 2013 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.
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/sample_main_layout">
+
+ <LinearLayout
+ android:id="@+id/sample_output"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:orientation="vertical">
+
+ <FrameLayout
+ style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/margin_medium"
+ android:paddingRight="@dimen/margin_medium"
+ android:paddingTop="@dimen/margin_large"
+ android:paddingBottom="@dimen/margin_large"
+ android:text="@string/intro_message" />
+ </FrameLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@android:color/darker_gray" />
+
+ <fragment
+ android:name="com.example.android.common.logger.LogFragment"
+ android:id="@+id/log_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1" />
+
+ </LinearLayout>
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:background="@android:color/darker_gray" />
+
+ <FrameLayout
+ android:id="@+id/sample_content_fragment"
+ android:layout_weight="2"
+ android:layout_width="0px"
+ android:layout_height="match_parent" />
+
+</LinearLayout>
+
+
diff --git a/samples/browseable/CardReader/res/layout/activity_main.xml b/samples/browseable/CardReader/res/layout/activity_main.xml
new file mode 100755
index 000000000..1ae4f981e
--- /dev/null
+++ b/samples/browseable/CardReader/res/layout/activity_main.xml
@@ -0,0 +1,65 @@
+<!--
+ Copyright 2013 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.
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/sample_main_layout">
+
+ <ViewAnimator
+ android:id="@+id/sample_output"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1">
+
+ <ScrollView
+ style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/horizontal_page_margin"
+ android:paddingRight="@dimen/horizontal_page_margin"
+ android:paddingTop="@dimen/vertical_page_margin"
+ android:paddingBottom="@dimen/vertical_page_margin"
+ android:text="@string/intro_message" />
+ </ScrollView>
+
+ <fragment
+ android:name="com.example.android.common.logger.LogFragment"
+ android:id="@+id/log_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ </ViewAnimator>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@android:color/darker_gray" />
+
+ <FrameLayout
+ android:id="@+id/sample_content_fragment"
+ android:layout_weight="2"
+ android:layout_width="match_parent"
+ android:layout_height="0px" />
+
+</LinearLayout>
+
diff --git a/samples/browseable/CardReader/res/layout/main_fragment.xml b/samples/browseable/CardReader/res/layout/main_fragment.xml
new file mode 100644
index 000000000..1e3886c76
--- /dev/null
+++ b/samples/browseable/CardReader/res/layout/main_fragment.xml
@@ -0,0 +1,64 @@
+<!--
+Copyright (C) 2013 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.
+-->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="380dp"
+ android:layout_height="242.25dp"
+ android:layout_gravity="center"
+ android:layout_margin="20dp">
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:src="@drawable/card_background"
+ />
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:padding="20dp"
+ android:layout_gravity="center"
+ android:clickable="true">
+ <TextView
+ android:id="@+id/card_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/card_title"
+ android:fontFamily="sans-serif-condensed"
+ android:textStyle="bold"
+ android:textSize="32dp"
+ />
+ <TextView
+ android:id="@+id/card_account_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/account_number"
+ android:fontFamily="sans-serif"
+ android:textStyle="bold"
+ android:textSize="18dp"
+ android:layout_marginTop="40dp"
+ />
+ <TextView
+ android:id="@+id/card_account_field"
+ android:width="360dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:fontFamily="sans-serif-condensed"
+ android:textStyle="bold"
+ android:textSize="42dp"
+ android:singleLine="true"
+ />
+ </LinearLayout>
+</FrameLayout> \ No newline at end of file
diff --git a/samples/browseable/CardReader/res/menu/main.xml b/samples/browseable/CardReader/res/menu/main.xml
new file mode 100644
index 000000000..b49c2c526
--- /dev/null
+++ b/samples/browseable/CardReader/res/menu/main.xml
@@ -0,0 +1,21 @@
+<!--
+ Copyright 2013 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.
+ -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/menu_toggle_log"
+ android:showAsAction="always"
+ android:title="@string/sample_show_log" />
+</menu>
diff --git a/samples/browseable/HorizontalPaging/res/values-sw600dp/dimens.xml b/samples/browseable/CardReader/res/values-sw600dp/template-dimens.xml
index 22074a2bd..22074a2bd 100644
--- a/samples/browseable/HorizontalPaging/res/values-sw600dp/dimens.xml
+++ b/samples/browseable/CardReader/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/HorizontalPaging/res/values-sw600dp/styles.xml b/samples/browseable/CardReader/res/values-sw600dp/template-styles.xml
index 03d197418..03d197418 100644
--- a/samples/browseable/HorizontalPaging/res/values-sw600dp/styles.xml
+++ b/samples/browseable/CardReader/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/CardReader/res/values/base-strings.xml b/samples/browseable/CardReader/res/values/base-strings.xml
new file mode 100644
index 000000000..ac1248054
--- /dev/null
+++ b/samples/browseable/CardReader/res/values/base-strings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+ <string name="app_name">CardReader</string>
+ <string name="intro_message">
+ <![CDATA[
+
+
+ This sample demonstrates how to implement a low-level NFC card reader, for reading cards
+ that do not contain NDEF or Android Beam data. This sample is designed to read the virtual
+ loyalty card implemented in the "CardEmulation" sample.\n\n
+
+ In particular, this sample demonstrates how to disable Android Beam, select which AIDs the
+ reader is interested, and establish communication with the card
+
+
+ ]]>
+ </string>
+</resources>
diff --git a/samples/browseable/CardReader/res/values/strings.xml b/samples/browseable/CardReader/res/values/strings.xml
new file mode 100755
index 000000000..7b9d9ec4f
--- /dev/null
+++ b/samples/browseable/CardReader/res/values/strings.xml
@@ -0,0 +1,19 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="sample_show_log">Show Log</string>
+ <string name="sample_hide_log">Hide Log</string>
+</resources>
diff --git a/samples/browseable/CardReader/res/values/template-dimens.xml b/samples/browseable/CardReader/res/values/template-dimens.xml
new file mode 100644
index 000000000..39e710b5c
--- /dev/null
+++ b/samples/browseable/CardReader/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/CardReader/res/values/template-styles.xml b/samples/browseable/CardReader/res/values/template-styles.xml
new file mode 100644
index 000000000..404623e3d
--- /dev/null
+++ b/samples/browseable/CardReader/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/CardReader/res/xml/nfc_tech_filter.xml b/samples/browseable/CardReader/res/xml/nfc_tech_filter.xml
new file mode 100644
index 000000000..dcfc97911
--- /dev/null
+++ b/samples/browseable/CardReader/res/xml/nfc_tech_filter.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- This file is used as part of the filter for incoming NFC TECH_DISCOVERED intents. -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- Android's host card emulation feature only supports the IsoDep protocol. -->
+ <tech-list>
+ <tech>android.nfc.tech.IsoDep</tech>
+ </tech-list>
+</resources> \ No newline at end of file
diff --git a/samples/browseable/CardReader/src/com.example.android.cardreader/CardReaderFragment.java b/samples/browseable/CardReader/src/com.example.android.cardreader/CardReaderFragment.java
new file mode 100644
index 000000000..3f27e9b4c
--- /dev/null
+++ b/samples/browseable/CardReader/src/com.example.android.cardreader/CardReaderFragment.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2013 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.example.android.cardreader;
+
+import android.app.Activity;
+import android.nfc.NfcAdapter;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.example.android.common.logger.Log;
+
+/**
+ * Generic UI for sample discovery.
+ */
+public class CardReaderFragment extends Fragment implements LoyaltyCardReader.AccountCallback {
+
+ public static final String TAG = "CardReaderFragment";
+ // Recommend NfcAdapter flags for reading from other Android devices. Indicates that this
+ // activity is interested in NFC-A devices (including other Android devices), and that the
+ // system should not check for the presence of NDEF-formatted data (e.g. Android Beam).
+ public static int READER_FLAGS =
+ NfcAdapter.FLAG_READER_NFC_A | NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK;
+ public LoyaltyCardReader mLoyaltyCardReader;
+ private TextView mAccountField;
+
+ /** Called when sample is created. Displays generic UI with welcome text. */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ View v = inflater.inflate(R.layout.main_fragment, container, false);
+ if (v != null) {
+ mAccountField = (TextView) v.findViewById(R.id.card_account_field);
+ mAccountField.setText("Waiting...");
+
+ mLoyaltyCardReader = new LoyaltyCardReader(this);
+
+ // Disable Android Beam and register our card reader callback
+ enableReaderMode();
+ }
+
+ return v;
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ disableReaderMode();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ enableReaderMode();
+ }
+
+ private void enableReaderMode() {
+ Log.i(TAG, "Enabling reader mode");
+ Activity activity = getActivity();
+ NfcAdapter nfc = NfcAdapter.getDefaultAdapter(activity);
+ if (nfc != null) {
+ nfc.enableReaderMode(activity, mLoyaltyCardReader, READER_FLAGS, null);
+ }
+ }
+
+ private void disableReaderMode() {
+ Log.i(TAG, "Disabling reader mode");
+ Activity activity = getActivity();
+ NfcAdapter nfc = NfcAdapter.getDefaultAdapter(activity);
+ if (nfc != null) {
+ nfc.disableReaderMode(activity);
+ }
+ }
+
+ @Override
+ public void onAccountReceived(final String account) {
+ // This callback is run on a background thread, but updates to UI elements must be performed
+ // on the UI thread.
+ getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mAccountField.setText(account);
+ }
+ });
+ }
+}
diff --git a/samples/browseable/CardReader/src/com.example.android.cardreader/LoyaltyCardReader.java b/samples/browseable/CardReader/src/com.example.android.cardreader/LoyaltyCardReader.java
new file mode 100644
index 000000000..c29bdfdea
--- /dev/null
+++ b/samples/browseable/CardReader/src/com.example.android.cardreader/LoyaltyCardReader.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2013 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.example.android.cardreader;
+
+import android.nfc.NfcAdapter;
+import android.nfc.Tag;
+import android.nfc.tech.IsoDep;
+
+import com.example.android.common.logger.Log;
+
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+import java.util.Arrays;
+
+/**
+ * Callback class, invoked when an NFC card is scanned while the device is running in reader mode.
+ *
+ * Reader mode can be invoked by calling NfcAdapter
+ */
+public class LoyaltyCardReader implements NfcAdapter.ReaderCallback {
+ private static final String TAG = "LoyaltyCardReader";
+ // AID for our loyalty card service.
+ private static final String SAMPLE_LOYALTY_CARD_AID = "F222222222";
+ // ISO-DEP command HEADER for selecting an AID.
+ // Format: [Class | Instruction | Parameter 1 | Parameter 2]
+ private static final String SELECT_APDU_HEADER = "00A40400";
+ // "OK" status word sent in response to SELECT AID command (0x9000)
+ private static final byte[] SELECT_OK_SW = {(byte) 0x90, (byte) 0x00};
+
+ // Weak reference to prevent retain loop. mAccountCallback is responsible for exiting
+ // foreground mode before it becomes invalid (e.g. during onPause() or onStop()).
+ private WeakReference<AccountCallback> mAccountCallback;
+
+ public interface AccountCallback {
+ public void onAccountReceived(String account);
+ }
+
+ public LoyaltyCardReader(AccountCallback accountCallback) {
+ mAccountCallback = new WeakReference<AccountCallback>(accountCallback);
+ }
+
+ /**
+ * Callback when a new tag is discovered by the system.
+ *
+ * <p>Communication with the card should take place here.
+ *
+ * @param tag Discovered tag
+ */
+ @Override
+ public void onTagDiscovered(Tag tag) {
+ Log.i(TAG, "New tag discovered");
+ // Android's Host-based Card Emulation (HCE) feature implements the ISO-DEP (ISO 14443-4)
+ // protocol.
+ //
+ // In order to communicate with a device using HCE, the discovered tag should be processed
+ // using the IsoDep class.
+ IsoDep isoDep = IsoDep.get(tag);
+ if (isoDep != null) {
+ try {
+ // Connect to the remote NFC device
+ isoDep.connect();
+ // Build SELECT AID command for our loyalty card service.
+ // This command tells the remote device which service we wish to communicate with.
+ Log.i(TAG, "Requesting remote AID: " + SAMPLE_LOYALTY_CARD_AID);
+ byte[] command = BuildSelectApdu(SAMPLE_LOYALTY_CARD_AID);
+ // Send command to remote device
+ Log.i(TAG, "Sending: " + ByteArrayToHexString(command));
+ byte[] result = isoDep.transceive(command);
+ // If AID is successfully selected, 0x9000 is returned as the status word (last 2
+ // bytes of the result) by convention. Everything before the status word is
+ // optional payload, which is used here to hold the account number.
+ int resultLength = result.length;
+ byte[] statusWord = {result[resultLength-2], result[resultLength-1]};
+ byte[] payload = Arrays.copyOf(result, resultLength-2);
+ if (Arrays.equals(SELECT_OK_SW, statusWord)) {
+ // The remote NFC device will immediately respond with its stored account number
+ String accountNumber = new String(payload, "UTF-8");
+ Log.i(TAG, "Received: " + accountNumber);
+ // Inform CardReaderFragment of received account number
+ mAccountCallback.get().onAccountReceived(accountNumber);
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Error communicating with card: " + e.toString());
+ }
+ }
+ }
+
+ /**
+ * Build APDU for SELECT AID command. This command indicates which service a reader is
+ * interested in communicating with. See ISO 7816-4.
+ *
+ * @param aid Application ID (AID) to select
+ * @return APDU for SELECT AID command
+ */
+ public static byte[] BuildSelectApdu(String aid) {
+ // Format: [CLASS | INSTRUCTION | PARAMETER 1 | PARAMETER 2 | LENGTH | DATA]
+ return HexStringToByteArray(SELECT_APDU_HEADER + String.format("%02X", aid.length() / 2) + aid);
+ }
+
+ /**
+ * Utility class to convert a byte array to a hexadecimal string.
+ *
+ * @param bytes Bytes to convert
+ * @return String, containing hexadecimal representation.
+ */
+ public static String ByteArrayToHexString(byte[] bytes) {
+ final char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+ char[] hexChars = new char[bytes.length * 2];
+ int v;
+ for ( int j = 0; j < bytes.length; j++ ) {
+ v = bytes[j] & 0xFF;
+ hexChars[j * 2] = hexArray[v >>> 4];
+ hexChars[j * 2 + 1] = hexArray[v & 0x0F];
+ }
+ return new String(hexChars);
+ }
+
+ /**
+ * Utility class to convert a hexadecimal string to a byte string.
+ *
+ * <p>Behavior with input strings containing non-hexadecimal characters is undefined.
+ *
+ * @param s String containing hexadecimal characters to convert
+ * @return Byte array generated from input
+ */
+ public static byte[] HexStringToByteArray(String s) {
+ int len = s.length();
+ byte[] data = new byte[len / 2];
+ for (int i = 0; i < len; i += 2) {
+ data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ + Character.digit(s.charAt(i+1), 16));
+ }
+ return data;
+ }
+
+}
diff --git a/samples/browseable/CardReader/src/com.example.android.cardreader/MainActivity.java b/samples/browseable/CardReader/src/com.example.android.cardreader/MainActivity.java
new file mode 100644
index 000000000..e0280e998
--- /dev/null
+++ b/samples/browseable/CardReader/src/com.example.android.cardreader/MainActivity.java
@@ -0,0 +1,110 @@
+/*
+* Copyright 2013 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.example.android.cardreader;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.ViewAnimator;
+
+import com.example.android.common.activities.SampleActivityBase;
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogFragment;
+import com.example.android.common.logger.LogWrapper;
+import com.example.android.common.logger.MessageOnlyLogFilter;
+
+/**
+ * A simple launcher activity containing a summary sample description, sample log and a custom
+ * {@link android.support.v4.app.Fragment} which can display a view.
+ * <p>
+ * For devices with displays with a width of 720dp or greater, the sample log is always visible,
+ * on other devices it's visibility is controlled by an item on the Action Bar.
+ */
+public class MainActivity extends SampleActivityBase {
+
+ public static final String TAG = "MainActivity";
+
+ // Whether the Log Fragment is currently shown
+ private boolean mLogShown;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+ CardReaderFragment fragment = new CardReaderFragment();
+ transaction.replace(R.id.sample_content_fragment, fragment);
+ transaction.commit();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.main, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ MenuItem logToggle = menu.findItem(R.id.menu_toggle_log);
+ logToggle.setVisible(findViewById(R.id.sample_output) instanceof ViewAnimator);
+ logToggle.setTitle(mLogShown ? R.string.sample_hide_log : R.string.sample_show_log);
+
+ return super.onPrepareOptionsMenu(menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch(item.getItemId()) {
+ case R.id.menu_toggle_log:
+ mLogShown = !mLogShown;
+ ViewAnimator output = (ViewAnimator) findViewById(R.id.sample_output);
+ if (mLogShown) {
+ output.setDisplayedChild(1);
+ } else {
+ output.setDisplayedChild(0);
+ }
+ supportInvalidateOptionsMenu();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ /** Create a chain of targets that will receive log data */
+ @Override
+ public void initializeLogging() {
+ // Wraps Android's native log framework.
+ LogWrapper logWrapper = new LogWrapper();
+ // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+ Log.setLogNode(logWrapper);
+
+ // Filter strips out everything except the message text.
+ MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
+ logWrapper.setNext(msgFilter);
+
+ // On screen logging via a fragment with a TextView.
+ LogFragment logFragment = (LogFragment) getSupportFragmentManager()
+ .findFragmentById(R.id.log_fragment);
+ msgFilter.setNext(logFragment.getLogView());
+
+ Log.i(TAG, "Ready");
+ }
+}
diff --git a/samples/browseable/CardReader/src/com.example.android.common/activities/SampleActivityBase.java b/samples/browseable/CardReader/src/com.example.android.common/activities/SampleActivityBase.java
new file mode 100644
index 000000000..3228927b7
--- /dev/null
+++ b/samples/browseable/CardReader/src/com.example.android.common/activities/SampleActivityBase.java
@@ -0,0 +1,52 @@
+/*
+* Copyright 2013 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.example.android.common.activities;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogWrapper;
+
+/**
+ * Base launcher activity, to handle most of the common plumbing for samples.
+ */
+public class SampleActivityBase extends FragmentActivity {
+
+ public static final String TAG = "SampleActivityBase";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ initializeLogging();
+ }
+
+ /** Set up targets to receive log data */
+ public void initializeLogging() {
+ // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+ // Wraps Android's native log framework
+ LogWrapper logWrapper = new LogWrapper();
+ Log.setLogNode(logWrapper);
+
+ Log.i(TAG, "Ready");
+ }
+}
diff --git a/samples/browseable/CardReader/src/com.example.android.common/logger/Log.java b/samples/browseable/CardReader/src/com.example.android.common/logger/Log.java
new file mode 100644
index 000000000..17503c568
--- /dev/null
+++ b/samples/browseable/CardReader/src/com.example.android.common/logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 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.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+ // Grabbing the native values from Android's native logging facilities,
+ // to make for easy migration and interop.
+ public static final int NONE = -1;
+ public static final int VERBOSE = android.util.Log.VERBOSE;
+ public static final int DEBUG = android.util.Log.DEBUG;
+ public static final int INFO = android.util.Log.INFO;
+ public static final int WARN = android.util.Log.WARN;
+ public static final int ERROR = android.util.Log.ERROR;
+ public static final int ASSERT = android.util.Log.ASSERT;
+
+ // Stores the beginning of the LogNode topology.
+ private static LogNode mLogNode;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public static LogNode getLogNode() {
+ return mLogNode;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to.
+ */
+ public static void setLogNode(LogNode node) {
+ mLogNode = node;
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void println(int priority, String tag, String msg, Throwable tr) {
+ if (mLogNode != null) {
+ mLogNode.println(priority, tag, msg, tr);
+ }
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ */
+ public static void println(int priority, String tag, String msg) {
+ println(priority, tag, msg, null);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void v(String tag, String msg, Throwable tr) {
+ println(VERBOSE, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void v(String tag, String msg) {
+ v(tag, msg, null);
+ }
+
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void d(String tag, String msg, Throwable tr) {
+ println(DEBUG, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void d(String tag, String msg) {
+ d(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void i(String tag, String msg, Throwable tr) {
+ println(INFO, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void i(String tag, String msg) {
+ i(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, String msg, Throwable tr) {
+ println(WARN, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void w(String tag, String msg) {
+ w(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, Throwable tr) {
+ w(tag, null, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void e(String tag, String msg, Throwable tr) {
+ println(ERROR, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void e(String tag, String msg) {
+ e(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, String msg, Throwable tr) {
+ println(ASSERT, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void wtf(String tag, String msg) {
+ wtf(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, Throwable tr) {
+ wtf(tag, null, tr);
+ }
+}
diff --git a/samples/browseable/CardReader/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/CardReader/src/com.example.android.common/logger/LogFragment.java
new file mode 100644
index 000000000..b302acd4b
--- /dev/null
+++ b/samples/browseable/CardReader/src/com.example.android.common/logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 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.
+*/
+/*
+ * Copyright 2013 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.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+ private LogView mLogView;
+ private ScrollView mScrollView;
+
+ public LogFragment() {}
+
+ public View inflateViews() {
+ mScrollView = new ScrollView(getActivity());
+ ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT);
+ mScrollView.setLayoutParams(scrollParams);
+
+ mLogView = new LogView(getActivity());
+ ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+ logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+ mLogView.setLayoutParams(logParams);
+ mLogView.setClickable(true);
+ mLogView.setFocusable(true);
+ mLogView.setTypeface(Typeface.MONOSPACE);
+
+ // Want to set padding as 16 dips, setPadding takes pixels. Hooray math!
+ int paddingDips = 16;
+ double scale = getResources().getDisplayMetrics().density;
+ int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+ mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+ mLogView.setCompoundDrawablePadding(paddingPixels);
+
+ mLogView.setGravity(Gravity.BOTTOM);
+ mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+ mScrollView.addView(mLogView);
+ return mScrollView;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+
+ View result = inflateViews();
+
+ mLogView.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+ }
+ });
+ return result;
+ }
+
+ public LogView getLogView() {
+ return mLogView;
+ }
+} \ No newline at end of file
diff --git a/samples/browseable/CardReader/src/com.example.android.common/logger/LogNode.java b/samples/browseable/CardReader/src/com.example.android.common/logger/LogNode.java
new file mode 100644
index 000000000..bc37cabc0
--- /dev/null
+++ b/samples/browseable/CardReader/src/com.example.android.common/logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * 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.example.android.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+ /**
+ * Instructs first LogNode in the list to print the log data provided.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/CardReader/src/com.example.android.common/logger/LogView.java b/samples/browseable/CardReader/src/com.example.android.common/logger/LogView.java
new file mode 100644
index 000000000..c01542b91
--- /dev/null
+++ b/samples/browseable/CardReader/src/com.example.android.common/logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 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.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+ public LogView(Context context) {
+ super(context);
+ }
+
+ public LogView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public LogView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ /**
+ * Formats the log data and prints it out to the LogView.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+
+
+ String priorityStr = null;
+
+ // For the purposes of this View, we want to print the priority as readable text.
+ switch(priority) {
+ case android.util.Log.VERBOSE:
+ priorityStr = "VERBOSE";
+ break;
+ case android.util.Log.DEBUG:
+ priorityStr = "DEBUG";
+ break;
+ case android.util.Log.INFO:
+ priorityStr = "INFO";
+ break;
+ case android.util.Log.WARN:
+ priorityStr = "WARN";
+ break;
+ case android.util.Log.ERROR:
+ priorityStr = "ERROR";
+ break;
+ case android.util.Log.ASSERT:
+ priorityStr = "ASSERT";
+ break;
+ default:
+ break;
+ }
+
+ // Handily, the Log class has a facility for converting a stack trace into a usable string.
+ String exceptionStr = null;
+ if (tr != null) {
+ exceptionStr = android.util.Log.getStackTraceString(tr);
+ }
+
+ // Take the priority, tag, message, and exception, and concatenate as necessary
+ // into one usable line of text.
+ final StringBuilder outputBuilder = new StringBuilder();
+
+ String delimiter = "\t";
+ appendIfNotNull(outputBuilder, priorityStr, delimiter);
+ appendIfNotNull(outputBuilder, tag, delimiter);
+ appendIfNotNull(outputBuilder, msg, delimiter);
+ appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+ // In case this was originally called from an AsyncTask or some other off-UI thread,
+ // make sure the update occurs within the UI thread.
+ ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+ @Override
+ public void run() {
+ // Display the text we just generated within the LogView.
+ appendToLog(outputBuilder.toString());
+ }
+ })));
+
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+ * the logger takes so many arguments that might be null, this method helps cut out some of the
+ * agonizing tedium of writing the same 3 lines over and over.
+ * @param source StringBuilder containing the text to append to.
+ * @param addStr The String to append
+ * @param delimiter The String to separate the source and appended strings. A tab or comma,
+ * for instance.
+ * @return The fully concatenated String as a StringBuilder
+ */
+ private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+ if (addStr != null) {
+ if (addStr.length() == 0) {
+ delimiter = "";
+ }
+
+ return source.append(addStr).append(delimiter);
+ }
+ return source;
+ }
+
+ // The next LogNode in the chain.
+ LogNode mNext;
+
+ /** Outputs the string as a new line of log data in the LogView. */
+ public void appendToLog(String s) {
+ append("\n" + s);
+ }
+
+
+}
diff --git a/samples/browseable/CardReader/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/CardReader/src/com.example.android.common/logger/LogWrapper.java
new file mode 100644
index 000000000..16a9e7ba2
--- /dev/null
+++ b/samples/browseable/CardReader/src/com.example.android.common/logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * 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.example.android.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface. This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+ // For piping: The next node to receive Log data after this one has done its work.
+ private LogNode mNext;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /**
+ * Prints data out to the console using Android's native log mechanism.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ // There actually are log methods that don't take a msg parameter. For now,
+ // if that's the case, just convert null to the empty string and move on.
+ String useMsg = msg;
+ if (useMsg == null) {
+ useMsg = "";
+ }
+
+ // If an exeption was provided, convert that exception to a usable string and attach
+ // it to the end of the msg method.
+ if (tr != null) {
+ msg += "\n" + Log.getStackTraceString(tr);
+ }
+
+ // This is functionally identical to Log.x(tag, useMsg);
+ // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+ Log.println(priority, tag, useMsg);
+
+ // If this isn't the last node in the chain, move things along.
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+}
diff --git a/samples/browseable/CardReader/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/CardReader/src/com.example.android.common/logger/MessageOnlyLogFilter.java
new file mode 100644
index 000000000..19967dcd4
--- /dev/null
+++ b/samples/browseable/CardReader/src/com.example.android.common/logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 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.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+ LogNode mNext;
+
+ /**
+ * Takes the "next" LogNode as a parameter, to simplify chaining.
+ *
+ * @param next The next LogNode in the pipeline.
+ */
+ public MessageOnlyLogFilter(LogNode next) {
+ mNext = next;
+ }
+
+ public MessageOnlyLogFilter() {
+ }
+
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ if (mNext != null) {
+ getNext().println(Log.NONE, null, msg, null);
+ }
+ }
+
+ /**
+ * Returns the next LogNode in the chain.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+}
diff --git a/samples/browseable/ImmersiveMode/res/values-sw600dp/dimens.xml b/samples/browseable/CustomChoiceList/res/values-sw600dp/template-dimens.xml
index 22074a2bd..22074a2bd 100644
--- a/samples/browseable/ImmersiveMode/res/values-sw600dp/dimens.xml
+++ b/samples/browseable/CustomChoiceList/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/ImmersiveMode/res/values-sw600dp/styles.xml b/samples/browseable/CustomChoiceList/res/values-sw600dp/template-styles.xml
index 03d197418..03d197418 100644
--- a/samples/browseable/ImmersiveMode/res/values-sw600dp/styles.xml
+++ b/samples/browseable/CustomChoiceList/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/CustomChoiceList/res/values/dimens.xml b/samples/browseable/CustomChoiceList/res/values/dimens.xml
index 39e710b5c..c22027efa 100644
--- a/samples/browseable/CustomChoiceList/res/values/dimens.xml
+++ b/samples/browseable/CustomChoiceList/res/values/dimens.xml
@@ -16,17 +16,8 @@
<resources>
- <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+ <!-- Meta-dimension that switches on screen size -->
- <dimen name="margin_tiny">4dp</dimen>
- <dimen name="margin_small">8dp</dimen>
- <dimen name="margin_medium">16dp</dimen>
- <dimen name="margin_large">32dp</dimen>
- <dimen name="margin_huge">64dp</dimen>
-
- <!-- Semantic definitions -->
-
- <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
- <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="page_margin">@dimen/margin_medium</dimen>
</resources>
diff --git a/samples/browseable/CustomChoiceList/res/values/styles.xml b/samples/browseable/CustomChoiceList/res/values/styles.xml
index 404623e3d..0851a81fa 100644
--- a/samples/browseable/CustomChoiceList/res/values/styles.xml
+++ b/samples/browseable/CustomChoiceList/res/values/styles.xml
@@ -15,28 +15,14 @@
-->
<resources>
-
- <!-- Activity themes -->
-
- <style name="Theme.Base" parent="android:Theme.Holo.Light" />
-
- <style name="Theme.Sample" parent="Theme.Base" />
-
- <style name="AppTheme" parent="Theme.Sample" />
- <!-- Widget styling -->
-
- <style name="Widget" />
-
- <style name="Widget.SampleMessage">
+ <style name="Widget.DescriptionBar">
+ <item name="android:background">#fb3</item>
+ <item name="android:paddingTop">@dimen/margin_medium</item>
+ <item name="android:paddingBottom">@dimen/margin_medium</item>
+ <item name="android:paddingLeft">@dimen/page_margin</item>
+ <item name="android:paddingRight">@dimen/page_margin</item>
<item name="android:textAppearance">?android:textAppearanceMedium</item>
<item name="android:lineSpacingMultiplier">1.1</item>
</style>
- <style name="Widget.SampleMessageTile">
- <item name="android:background">@drawable/tile</item>
- <item name="android:shadowColor">#7F000000</item>
- <item name="android:shadowDy">-3.5</item>
- <item name="android:shadowRadius">2</item>
- </style>
-
</resources>
diff --git a/samples/browseable/CustomChoiceList/res/values/template-dimens.xml b/samples/browseable/CustomChoiceList/res/values/template-dimens.xml
new file mode 100644
index 000000000..39e710b5c
--- /dev/null
+++ b/samples/browseable/CustomChoiceList/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/CustomChoiceList/res/values/template-styles.xml b/samples/browseable/CustomChoiceList/res/values/template-styles.xml
new file mode 100644
index 000000000..404623e3d
--- /dev/null
+++ b/samples/browseable/CustomChoiceList/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/NetworkConnect/res/values-sw600dp/dimens.xml b/samples/browseable/CustomNotifications/res/values-sw600dp/template-dimens.xml
index 22074a2bd..22074a2bd 100644
--- a/samples/browseable/NetworkConnect/res/values-sw600dp/dimens.xml
+++ b/samples/browseable/CustomNotifications/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/NetworkConnect/res/values-sw600dp/styles.xml b/samples/browseable/CustomNotifications/res/values-sw600dp/template-styles.xml
index 03d197418..03d197418 100644
--- a/samples/browseable/NetworkConnect/res/values-sw600dp/styles.xml
+++ b/samples/browseable/CustomNotifications/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/CustomNotifications/res/values/dimens.xml b/samples/browseable/CustomNotifications/res/values/dimens.xml
index 39e710b5c..ca1b9e61b 100644
--- a/samples/browseable/CustomNotifications/res/values/dimens.xml
+++ b/samples/browseable/CustomNotifications/res/values/dimens.xml
@@ -1,32 +1,20 @@
<!--
- Copyright 2013 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.
+ * Copyright (C) 2013 The Android Open Source Project
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
-->
<resources>
-
- <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
-
- <dimen name="margin_tiny">4dp</dimen>
- <dimen name="margin_small">8dp</dimen>
- <dimen name="margin_medium">16dp</dimen>
- <dimen name="margin_large">32dp</dimen>
- <dimen name="margin_huge">64dp</dimen>
-
- <!-- Semantic definitions -->
-
- <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
- <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
-
+ <!-- Default screen margins, per the Android Design guidelines. -->
+ <dimen name="activity_horizontal_margin">16dp</dimen>
+ <dimen name="activity_vertical_margin">16dp</dimen>
</resources>
diff --git a/samples/browseable/CustomNotifications/res/values/styles.xml b/samples/browseable/CustomNotifications/res/values/styles.xml
index 404623e3d..1d3d45b41 100644
--- a/samples/browseable/CustomNotifications/res/values/styles.xml
+++ b/samples/browseable/CustomNotifications/res/values/styles.xml
@@ -1,42 +1,22 @@
<!--
- Copyright 2013 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.
+ * Copyright (C) 2013 The Android Open Source Project
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
-->
<resources>
- <!-- Activity themes -->
-
- <style name="Theme.Base" parent="android:Theme.Holo.Light" />
-
- <style name="Theme.Sample" parent="Theme.Base" />
-
- <style name="AppTheme" parent="Theme.Sample" />
- <!-- Widget styling -->
-
- <style name="Widget" />
-
- <style name="Widget.SampleMessage">
- <item name="android:textAppearance">?android:textAppearanceMedium</item>
- <item name="android:lineSpacingMultiplier">1.1</item>
- </style>
-
- <style name="Widget.SampleMessageTile">
- <item name="android:background">@drawable/tile</item>
- <item name="android:shadowColor">#7F000000</item>
- <item name="android:shadowDy">-3.5</item>
- <item name="android:shadowRadius">2</item>
+ <style name="NotificationContent" parent="@android:style/TextAppearance.Small">
+ <item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
</style>
</resources>
diff --git a/samples/browseable/CustomNotifications/res/values/template-dimens.xml b/samples/browseable/CustomNotifications/res/values/template-dimens.xml
new file mode 100644
index 000000000..39e710b5c
--- /dev/null
+++ b/samples/browseable/CustomNotifications/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/CustomNotifications/res/values/template-styles.xml b/samples/browseable/CustomNotifications/res/values/template-styles.xml
new file mode 100644
index 000000000..404623e3d
--- /dev/null
+++ b/samples/browseable/CustomNotifications/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/StorageClient/res/values-sw600dp/dimens.xml b/samples/browseable/DoneBar/res/values-sw600dp/template-dimens.xml
index 22074a2bd..22074a2bd 100644
--- a/samples/browseable/StorageClient/res/values-sw600dp/dimens.xml
+++ b/samples/browseable/DoneBar/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/StorageClient/res/values-sw600dp/styles.xml b/samples/browseable/DoneBar/res/values-sw600dp/template-styles.xml
index 03d197418..03d197418 100644
--- a/samples/browseable/StorageClient/res/values-sw600dp/styles.xml
+++ b/samples/browseable/DoneBar/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/DoneBar/res/values/template-dimens.xml b/samples/browseable/DoneBar/res/values/template-dimens.xml
new file mode 100644
index 000000000..39e710b5c
--- /dev/null
+++ b/samples/browseable/DoneBar/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/DoneBar/res/values/styles.xml b/samples/browseable/DoneBar/res/values/template-styles.xml
index cafe531a4..cafe531a4 100644
--- a/samples/browseable/DoneBar/res/values/styles.xml
+++ b/samples/browseable/DoneBar/res/values/template-styles.xml
diff --git a/samples/browseable/TextLinkify/res/values-sw600dp/dimens.xml b/samples/browseable/HorizontalPaging/res/values-sw600dp/template-dimens.xml
index 22074a2bd..22074a2bd 100644
--- a/samples/browseable/TextLinkify/res/values-sw600dp/dimens.xml
+++ b/samples/browseable/HorizontalPaging/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/TextLinkify/res/values-sw600dp/styles.xml b/samples/browseable/HorizontalPaging/res/values-sw600dp/template-styles.xml
index 03d197418..03d197418 100644
--- a/samples/browseable/TextLinkify/res/values-sw600dp/styles.xml
+++ b/samples/browseable/HorizontalPaging/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/HorizontalPaging/res/values/dimens.xml b/samples/browseable/HorizontalPaging/res/values/dimens.xml
index 39e710b5c..47c822467 100644
--- a/samples/browseable/HorizontalPaging/res/values/dimens.xml
+++ b/samples/browseable/HorizontalPaging/res/values/dimens.xml
@@ -1,32 +1,5 @@
-<!--
- Copyright 2013 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
<resources>
-
- <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
-
- <dimen name="margin_tiny">4dp</dimen>
- <dimen name="margin_small">8dp</dimen>
- <dimen name="margin_medium">16dp</dimen>
- <dimen name="margin_large">32dp</dimen>
- <dimen name="margin_huge">64dp</dimen>
-
- <!-- Semantic definitions -->
-
- <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
- <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
-
+ <!-- Default screen margins, per the Android Design guidelines. -->
+ <dimen name="activity_horizontal_margin">16dp</dimen>
+ <dimen name="activity_vertical_margin">16dp</dimen>
</resources>
diff --git a/samples/browseable/HorizontalPaging/res/values/template-dimens.xml b/samples/browseable/HorizontalPaging/res/values/template-dimens.xml
new file mode 100644
index 000000000..39e710b5c
--- /dev/null
+++ b/samples/browseable/HorizontalPaging/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/HorizontalPaging/res/values/template-styles.xml b/samples/browseable/HorizontalPaging/res/values/template-styles.xml
new file mode 100644
index 000000000..404623e3d
--- /dev/null
+++ b/samples/browseable/HorizontalPaging/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/repeatingAlarm/res/values-sw600dp/dimens.xml b/samples/browseable/ImmersiveMode/res/values-sw600dp/template-dimens.xml
index 22074a2bd..22074a2bd 100644
--- a/samples/browseable/repeatingAlarm/res/values-sw600dp/dimens.xml
+++ b/samples/browseable/ImmersiveMode/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/TextSwitcher/res/values-sw600dp/styles.xml b/samples/browseable/ImmersiveMode/res/values-sw600dp/template-styles.xml
index 03d197418..03d197418 100644
--- a/samples/browseable/TextSwitcher/res/values-sw600dp/styles.xml
+++ b/samples/browseable/ImmersiveMode/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/ImmersiveMode/res/values/template-dimens.xml b/samples/browseable/ImmersiveMode/res/values/template-dimens.xml
new file mode 100644
index 000000000..39e710b5c
--- /dev/null
+++ b/samples/browseable/ImmersiveMode/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/BasicImmersiveMode/res/values/styles.xml b/samples/browseable/ImmersiveMode/res/values/template-styles.xml
index d3f82ff64..d3f82ff64 100644
--- a/samples/browseable/BasicImmersiveMode/res/values/styles.xml
+++ b/samples/browseable/ImmersiveMode/res/values/template-styles.xml
diff --git a/samples/browseable/MediaRecorder/res/drawable-hdpi/tile.9.png b/samples/browseable/MediaRecorder/res/drawable-hdpi/tile.9.png
new file mode 100644
index 000000000..135862883
--- /dev/null
+++ b/samples/browseable/MediaRecorder/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/MediaRecorder/res/layout/activity_main.xml b/samples/browseable/MediaRecorder/res/layout/activity_main.xml
new file mode 100755
index 000000000..be1aa49d9
--- /dev/null
+++ b/samples/browseable/MediaRecorder/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+ Copyright 2013 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.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <LinearLayout style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/horizontal_page_margin"
+ android:layout_marginRight="@dimen/horizontal_page_margin"
+ android:layout_marginTop="@dimen/vertical_page_margin"
+ android:layout_marginBottom="@dimen/vertical_page_margin"
+ android:text="@string/intro_message" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/MediaRecorder/res/values-sw600dp/template-dimens.xml b/samples/browseable/MediaRecorder/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 000000000..22074a2bd
--- /dev/null
+++ b/samples/browseable/MediaRecorder/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/repeatingAlarm/res/values-sw600dp/styles.xml b/samples/browseable/MediaRecorder/res/values-sw600dp/template-styles.xml
index 03d197418..03d197418 100644
--- a/samples/browseable/repeatingAlarm/res/values-sw600dp/styles.xml
+++ b/samples/browseable/MediaRecorder/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/MediaRecorder/res/values/base-strings.xml b/samples/browseable/MediaRecorder/res/values/base-strings.xml
new file mode 100644
index 000000000..f9ade8c45
--- /dev/null
+++ b/samples/browseable/MediaRecorder/res/values/base-strings.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+ <string name="app_name">MediaRecorder</string>
+ <string name="intro_message">
+ <![CDATA[
+
+
+ This sample uses the camera/camcorder as the A/V source for the MediaRecorder API.
+ A TextureView is used as the camera preview which limits the code to API 14+. This
+ can be easily replaced with a SurfaceView to run on older devices.
+
+
+ ]]>
+ </string>
+</resources>
diff --git a/samples/browseable/MediaRecorder/res/values/template-dimens.xml b/samples/browseable/MediaRecorder/res/values/template-dimens.xml
new file mode 100644
index 000000000..39e710b5c
--- /dev/null
+++ b/samples/browseable/MediaRecorder/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/MediaRecorder/res/values/template-styles.xml b/samples/browseable/MediaRecorder/res/values/template-styles.xml
new file mode 100644
index 000000000..404623e3d
--- /dev/null
+++ b/samples/browseable/MediaRecorder/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/MediaRecorder/src/com.example.android.common.media/CameraHelper.java b/samples/browseable/MediaRecorder/src/com.example.android.common.media/CameraHelper.java
new file mode 100644
index 000000000..1fa841675
--- /dev/null
+++ b/samples/browseable/MediaRecorder/src/com.example.android.common.media/CameraHelper.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2013 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.example.android.common.media;
+
+import android.annotation.TargetApi;
+import android.hardware.Camera;
+import android.os.Build;
+import android.os.Environment;
+import android.util.Log;
+
+import java.io.File;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Camera related utilities.
+ */
+public class CameraHelper {
+
+ public static final int MEDIA_TYPE_IMAGE = 1;
+ public static final int MEDIA_TYPE_VIDEO = 2;
+
+ /**
+ * Iterate over supported camera preview sizes to see which one best fits the
+ * dimensions of the given view while maintaining the aspect ratio. If none can,
+ * be lenient with the aspect ratio.
+ *
+ * @param sizes Supported camera preview sizes.
+ * @param w The width of the view.
+ * @param h The height of the view.
+ * @return Best match camera preview size to fit in the view.
+ */
+ public static Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
+ // Use a very small tolerance because we want an exact match.
+ final double ASPECT_TOLERANCE = 0.1;
+ double targetRatio = (double) w / h;
+ if (sizes == null)
+ return null;
+
+ Camera.Size optimalSize = null;
+
+ // Start with max value and refine as we iterate over available preview sizes. This is the
+ // minimum difference between view and camera height.
+ double minDiff = Double.MAX_VALUE;
+
+ // Target view height
+ int targetHeight = h;
+
+ // Try to find a preview size that matches aspect ratio and the target view size.
+ // Iterate over all available sizes and pick the largest size that can fit in the view and
+ // still maintain the aspect ratio.
+ for (Camera.Size size : sizes) {
+ double ratio = (double) size.width / size.height;
+ if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
+ continue;
+ if (Math.abs(size.height - targetHeight) < minDiff) {
+ optimalSize = size;
+ minDiff = Math.abs(size.height - targetHeight);
+ }
+ }
+
+ // Cannot find preview size that matches the aspect ratio, ignore the requirement
+ if (optimalSize == null) {
+ minDiff = Double.MAX_VALUE;
+ for (Camera.Size size : sizes) {
+ if (Math.abs(size.height - targetHeight) < minDiff) {
+ optimalSize = size;
+ minDiff = Math.abs(size.height - targetHeight);
+ }
+ }
+ }
+ return optimalSize;
+ }
+
+ /**
+ * @return the default camera on the device. Return null if there is no camera on the device.
+ */
+ public static Camera getDefaultCameraInstance() {
+ return Camera.open();
+ }
+
+
+ /**
+ * @return the default rear/back facing camera on the device. Returns null if camera is not
+ * available.
+ */
+ public static Camera getDefaultBackFacingCameraInstance() {
+ return getDefaultCamera(Camera.CameraInfo.CAMERA_FACING_BACK);
+ }
+
+ /**
+ * @return the default front facing camera on the device. Returns null if camera is not
+ * available.
+ */
+ public static Camera getDefaultFrontFacingCameraInstance() {
+ return getDefaultCamera(Camera.CameraInfo.CAMERA_FACING_FRONT);
+ }
+
+
+ /**
+ *
+ * @param position Physical position of the camera i.e Camera.CameraInfo.CAMERA_FACING_FRONT
+ * or Camera.CameraInfo.CAMERA_FACING_BACK.
+ * @return the default camera on the device. Returns null if camera is not available.
+ */
+ @TargetApi(Build.VERSION_CODES.GINGERBREAD)
+ private static Camera getDefaultCamera(int position) {
+ // Find the total number of cameras available
+ int mNumberOfCameras = Camera.getNumberOfCameras();
+
+ // Find the ID of the back-facing ("default") camera
+ Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
+ for (int i = 0; i < mNumberOfCameras; i++) {
+ Camera.getCameraInfo(i, cameraInfo);
+ if (cameraInfo.facing == position) {
+ return Camera.open(i);
+
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Creates a media file in the {@code Environment.DIRECTORY_PICTURES} directory. The directory
+ * is persistent and available to other applications like gallery.
+ *
+ * @param type Media type. Can be video or image.
+ * @return A file object pointing to the newly created file.
+ */
+ public static File getOutputMediaFile(int type){
+ // To be safe, you should check that the SDCard is mounted
+ // using Environment.getExternalStorageState() before doing this.
+ if (!Environment.getExternalStorageState().equalsIgnoreCase(Environment.MEDIA_MOUNTED)) {
+ return null;
+ }
+
+ File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
+ Environment.DIRECTORY_PICTURES), "CameraSample");
+ // This location works best if you want the created images to be shared
+ // between applications and persist after your app has been uninstalled.
+
+ // Create the storage directory if it does not exist
+ if (! mediaStorageDir.exists()){
+ if (! mediaStorageDir.mkdirs()) {
+ Log.d("CameraSample", "failed to create directory");
+ return null;
+ }
+ }
+
+ // Create a media file name
+ String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
+ File mediaFile;
+ if (type == MEDIA_TYPE_IMAGE){
+ mediaFile = new File(mediaStorageDir.getPath() + File.separator +
+ "IMG_"+ timeStamp + ".jpg");
+ } else if(type == MEDIA_TYPE_VIDEO) {
+ mediaFile = new File(mediaStorageDir.getPath() + File.separator +
+ "VID_"+ timeStamp + ".mp4");
+ } else {
+ return null;
+ }
+
+ return mediaFile;
+ }
+
+}
diff --git a/samples/browseable/MediaRecorder/src/com.example.android.common.media/MediaCodecWrapper.java b/samples/browseable/MediaRecorder/src/com.example.android.common.media/MediaCodecWrapper.java
new file mode 100644
index 000000000..a511221f5
--- /dev/null
+++ b/samples/browseable/MediaRecorder/src/com.example.android.common.media/MediaCodecWrapper.java
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2013 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.example.android.common.media;
+
+import android.media.*;
+import android.os.Handler;
+import android.os.Looper;
+import android.view.Surface;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayDeque;
+import java.util.Queue;
+
+/**
+ * Simplifies the MediaCodec interface by wrapping around the buffer processing operations.
+ */
+public class MediaCodecWrapper {
+
+ // Handler to use for {@code OutputSampleListener} and {code OutputFormatChangedListener}
+ // callbacks
+ private Handler mHandler;
+
+
+ // Callback when media output format changes.
+ public interface OutputFormatChangedListener {
+ void outputFormatChanged(MediaCodecWrapper sender, MediaFormat newFormat);
+ }
+
+ private OutputFormatChangedListener mOutputFormatChangedListener = null;
+
+ /**
+ * Callback for decodes frames. Observers can register a listener for optional stream
+ * of decoded data
+ */
+ public interface OutputSampleListener {
+ void outputSample(MediaCodecWrapper sender, MediaCodec.BufferInfo info, ByteBuffer buffer);
+ }
+
+ /**
+ * The {@link MediaCodec} that is managed by this class.
+ */
+ private MediaCodec mDecoder;
+
+ // References to the internal buffers managed by the codec. The codec
+ // refers to these buffers by index, never by reference so it's up to us
+ // to keep track of which buffer is which.
+ private ByteBuffer[] mInputBuffers;
+ private ByteBuffer[] mOutputBuffers;
+
+ // Indices of the input buffers that are currently available for writing. We'll
+ // consume these in the order they were dequeued from the codec.
+ private Queue<Integer> mAvailableInputBuffers;
+
+ // Indices of the output buffers that currently hold valid data, in the order
+ // they were produced by the codec.
+ private Queue<Integer> mAvailableOutputBuffers;
+
+ // Information about each output buffer, by index. Each entry in this array
+ // is valid if and only if its index is currently contained in mAvailableOutputBuffers.
+ private MediaCodec.BufferInfo[] mOutputBufferInfo;
+
+ // An (optional) stream that will receive decoded data.
+ private OutputSampleListener mOutputSampleListener;
+
+ private MediaCodecWrapper(MediaCodec codec) {
+ mDecoder = codec;
+ codec.start();
+ mInputBuffers = codec.getInputBuffers();
+ mOutputBuffers = codec.getOutputBuffers();
+ mOutputBufferInfo = new MediaCodec.BufferInfo[mOutputBuffers.length];
+ mAvailableInputBuffers = new ArrayDeque<Integer>(mOutputBuffers.length);
+ mAvailableOutputBuffers = new ArrayDeque<Integer>(mInputBuffers.length);
+ }
+
+ /**
+ * Releases resources and ends the encoding/decoding session.
+ */
+ public void stopAndRelease() {
+ mDecoder.stop();
+ mDecoder.release();
+ mDecoder = null;
+ mHandler = null;
+ }
+
+ /**
+ * Getter for the registered {@link OutputFormatChangedListener}
+ */
+ public OutputFormatChangedListener getOutputFormatChangedListener() {
+ return mOutputFormatChangedListener;
+ }
+
+ /**
+ *
+ * @param outputFormatChangedListener the listener for callback.
+ * @param handler message handler for posting the callback.
+ */
+ public void setOutputFormatChangedListener(final OutputFormatChangedListener
+ outputFormatChangedListener, Handler handler) {
+ mOutputFormatChangedListener = outputFormatChangedListener;
+
+ // Making sure we don't block ourselves due to a bad implementation of the callback by
+ // using a handler provided by client.
+ Looper looper;
+ mHandler = handler;
+ if (outputFormatChangedListener != null && mHandler == null) {
+ if ((looper = Looper.myLooper()) != null) {
+ mHandler = new Handler();
+ } else {
+ throw new IllegalArgumentException(
+ "Looper doesn't exist in the calling thread");
+ }
+ }
+ }
+
+ /**
+ * Constructs the {@link MediaCodecWrapper} wrapper object around the video codec.
+ * The codec is created using the encapsulated information in the
+ * {@link MediaFormat} object.
+ *
+ * @param trackFormat The format of the media object to be decoded.
+ * @param surface Surface to render the decoded frames.
+ * @return
+ */
+ public static MediaCodecWrapper fromVideoFormat(final MediaFormat trackFormat,
+ Surface surface) {
+ MediaCodecWrapper result = null;
+ MediaCodec videoCodec = null;
+
+ // BEGIN_INCLUDE(create_codec)
+ final String mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
+
+ // Check to see if this is actually a video mime type. If it is, then create
+ // a codec that can decode this mime type.
+ if (mimeType.contains("video/")) {
+ videoCodec = MediaCodec.createDecoderByType(mimeType);
+ videoCodec.configure(trackFormat, surface, null, 0);
+
+ }
+
+ // If codec creation was successful, then create a wrapper object around the
+ // newly created codec.
+ if (videoCodec != null) {
+ result = new MediaCodecWrapper(videoCodec);
+ }
+ // END_INCLUDE(create_codec)
+
+ return result;
+ }
+
+
+ /**
+ * Write a media sample to the decoder.
+ *
+ * A "sample" here refers to a single atomic access unit in the media stream. The definition
+ * of "access unit" is dependent on the type of encoding used, but it typically refers to
+ * a single frame of video or a few seconds of audio. {@link android.media.MediaExtractor}
+ * extracts data from a stream one sample at a time.
+ *
+ * @param input A ByteBuffer containing the input data for one sample. The buffer must be set
+ * up for reading, with its position set to the beginning of the sample data and its limit
+ * set to the end of the sample data.
+ *
+ * @param presentationTimeUs The time, relative to the beginning of the media stream,
+ * at which this buffer should be rendered.
+ *
+ * @param flags Flags to pass to the decoder. See {@link MediaCodec#queueInputBuffer(int,
+ * int, int, long, int)}
+ *
+ * @throws MediaCodec.CryptoException
+ */
+ public boolean writeSample(final ByteBuffer input,
+ final MediaCodec.CryptoInfo crypto,
+ final long presentationTimeUs,
+ final int flags) throws MediaCodec.CryptoException, WriteException {
+ boolean result = false;
+ int size = input.remaining();
+
+ // check if we have dequed input buffers available from the codec
+ if (size > 0 && !mAvailableInputBuffers.isEmpty()) {
+ int index = mAvailableInputBuffers.remove();
+ ByteBuffer buffer = mInputBuffers[index];
+
+ // we can't write our sample to a lesser capacity input buffer.
+ if (size > buffer.capacity()) {
+ throw new MediaCodecWrapper.WriteException(String.format(
+ "Insufficient capacity in MediaCodec buffer: "
+ + "tried to write %d, buffer capacity is %d.",
+ input.remaining(),
+ buffer.capacity()));
+ }
+
+ buffer.clear();
+ buffer.put(input);
+
+ // Submit the buffer to the codec for decoding. The presentationTimeUs
+ // indicates the position (play time) for the current sample.
+ if (crypto == null) {
+ mDecoder.queueInputBuffer(index, 0, size, presentationTimeUs, flags);
+ } else {
+ mDecoder.queueSecureInputBuffer(index, 0, crypto, presentationTimeUs, flags);
+ }
+ result = true;
+ }
+ return result;
+ }
+
+ static MediaCodec.CryptoInfo cryptoInfo= new MediaCodec.CryptoInfo();
+
+ /**
+ * Write a media sample to the decoder.
+ *
+ * A "sample" here refers to a single atomic access unit in the media stream. The definition
+ * of "access unit" is dependent on the type of encoding used, but it typically refers to
+ * a single frame of video or a few seconds of audio. {@link android.media.MediaExtractor}
+ * extracts data from a stream one sample at a time.
+ *
+ * @param extractor Instance of {@link android.media.MediaExtractor} wrapping the media.
+ *
+ * @param presentationTimeUs The time, relative to the beginning of the media stream,
+ * at which this buffer should be rendered.
+ *
+ * @param flags Flags to pass to the decoder. See {@link MediaCodec#queueInputBuffer(int,
+ * int, int, long, int)}
+ *
+ * @throws MediaCodec.CryptoException
+ */
+ public boolean writeSample(final MediaExtractor extractor,
+ final boolean isSecure,
+ final long presentationTimeUs,
+ int flags) {
+ boolean result = false;
+ boolean isEos = false;
+
+ if (!mAvailableInputBuffers.isEmpty()) {
+ int index = mAvailableInputBuffers.remove();
+ ByteBuffer buffer = mInputBuffers[index];
+
+ // reads the sample from the file using extractor into the buffer
+ int size = extractor.readSampleData(buffer, 0);
+ if (size <= 0) {
+ flags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
+ }
+
+ // Submit the buffer to the codec for decoding. The presentationTimeUs
+ // indicates the position (play time) for the current sample.
+ if (!isSecure) {
+ mDecoder.queueInputBuffer(index, 0, size, presentationTimeUs, flags);
+ } else {
+ extractor.getSampleCryptoInfo(cryptoInfo);
+ mDecoder.queueSecureInputBuffer(index, 0, cryptoInfo, presentationTimeUs, flags);
+ }
+
+ result = true;
+ }
+ return result;
+ }
+
+ /**
+ * Performs a peek() operation in the queue to extract media info for the buffer ready to be
+ * released i.e. the head element of the queue.
+ *
+ * @param out_bufferInfo An output var to hold the buffer info.
+ *
+ * @return True, if the peek was successful.
+ */
+ public boolean peekSample(MediaCodec.BufferInfo out_bufferInfo) {
+ // dequeue available buffers and synchronize our data structures with the codec.
+ update();
+ boolean result = false;
+ if (!mAvailableOutputBuffers.isEmpty()) {
+ int index = mAvailableOutputBuffers.peek();
+ MediaCodec.BufferInfo info = mOutputBufferInfo[index];
+ // metadata of the sample
+ out_bufferInfo.set(
+ info.offset,
+ info.size,
+ info.presentationTimeUs,
+ info.flags);
+ result = true;
+ }
+ return result;
+ }
+
+ /**
+ * Processes, releases and optionally renders the output buffer available at the head of the
+ * queue. All observers are notified with a callback. See {@link
+ * OutputSampleListener#outputSample(MediaCodecWrapper, android.media.MediaCodec.BufferInfo,
+ * java.nio.ByteBuffer)}
+ *
+ * @param render True, if the buffer is to be rendered on the {@link Surface} configured
+ *
+ */
+ public void popSample(boolean render) {
+ // dequeue available buffers and synchronize our data structures with the codec.
+ update();
+ if (!mAvailableOutputBuffers.isEmpty()) {
+ int index = mAvailableOutputBuffers.remove();
+
+ if (render && mOutputSampleListener != null) {
+ ByteBuffer buffer = mOutputBuffers[index];
+ MediaCodec.BufferInfo info = mOutputBufferInfo[index];
+ mOutputSampleListener.outputSample(this, info, buffer);
+ }
+
+ // releases the buffer back to the codec
+ mDecoder.releaseOutputBuffer(index, render);
+ }
+ }
+
+ /**
+ * Synchronize this object's state with the internal state of the wrapped
+ * MediaCodec.
+ */
+ private void update() {
+ // BEGIN_INCLUDE(update_codec_state)
+ int index;
+
+ // Get valid input buffers from the codec to fill later in the same order they were
+ // made available by the codec.
+ while ((index = mDecoder.dequeueInputBuffer(0)) != MediaCodec.INFO_TRY_AGAIN_LATER) {
+ mAvailableInputBuffers.add(index);
+ }
+
+
+ // Likewise with output buffers. If the output buffers have changed, start using the
+ // new set of output buffers. If the output format has changed, notify listeners.
+ MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
+ while ((index = mDecoder.dequeueOutputBuffer(info, 0)) != MediaCodec.INFO_TRY_AGAIN_LATER) {
+ switch (index) {
+ case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
+ mOutputBuffers = mDecoder.getOutputBuffers();
+ mOutputBufferInfo = new MediaCodec.BufferInfo[mOutputBuffers.length];
+ mAvailableOutputBuffers.clear();
+ break;
+ case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
+ if (mOutputFormatChangedListener != null) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mOutputFormatChangedListener
+ .outputFormatChanged(MediaCodecWrapper.this,
+ mDecoder.getOutputFormat());
+
+ }
+ });
+ }
+ break;
+ default:
+ // Making sure the index is valid before adding to output buffers. We've already
+ // handled INFO_TRY_AGAIN_LATER, INFO_OUTPUT_FORMAT_CHANGED &
+ // INFO_OUTPUT_BUFFERS_CHANGED i.e all the other possible return codes but
+ // asserting index value anyways for future-proofing the code.
+ if(index >= 0) {
+ mOutputBufferInfo[index] = info;
+ mAvailableOutputBuffers.add(index);
+ } else {
+ throw new IllegalStateException("Unknown status from dequeueOutputBuffer");
+ }
+ break;
+ }
+
+ }
+ // END_INCLUDE(update_codec_state)
+
+ }
+
+ private class WriteException extends Throwable {
+ private WriteException(final String detailMessage) {
+ super(detailMessage);
+ }
+ }
+}
diff --git a/samples/browseable/NetworkConnect/res/values-sw600dp/template-dimens.xml b/samples/browseable/NetworkConnect/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 000000000..22074a2bd
--- /dev/null
+++ b/samples/browseable/NetworkConnect/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/NetworkConnect/res/values-sw600dp/template-styles.xml b/samples/browseable/NetworkConnect/res/values-sw600dp/template-styles.xml
new file mode 100644
index 000000000..03d197418
--- /dev/null
+++ b/samples/browseable/NetworkConnect/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceLarge</item>
+ <item name="android:lineSpacingMultiplier">1.2</item>
+ <item name="android:shadowDy">-6.5</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/NetworkConnect/res/values/template-dimens.xml b/samples/browseable/NetworkConnect/res/values/template-dimens.xml
new file mode 100644
index 000000000..39e710b5c
--- /dev/null
+++ b/samples/browseable/NetworkConnect/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/NetworkConnect/res/values/template-styles.xml b/samples/browseable/NetworkConnect/res/values/template-styles.xml
new file mode 100644
index 000000000..404623e3d
--- /dev/null
+++ b/samples/browseable/NetworkConnect/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/RenderScriptIntrinsic/AndroidManifest.xml b/samples/browseable/RenderScriptIntrinsic/AndroidManifest.xml
new file mode 100644
index 000000000..566ef8ae7
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/AndroidManifest.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+ Copyright 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.renderscriptintrinsic"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <uses-sdk
+ android:minSdkVersion="8"
+ android:targetSdkVersion="19" />
+
+ <application
+ android:allowBackup="true"
+ android:label="RenderScriptIntrinsic"
+ android:icon="@drawable/ic_launcher"
+ android:theme="@style/AppTheme">
+
+ <activity
+ android:name=".MainActivity"
+ android:label="RenderScriptIntrinsic"
+ android:theme="@style/FullscreenTheme">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+
+</manifest>
diff --git a/samples/browseable/RenderScriptIntrinsic/_index.jd b/samples/browseable/RenderScriptIntrinsic/_index.jd
new file mode 100644
index 000000000..b9222aaa4
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/_index.jd
@@ -0,0 +1,14 @@
+
+
+
+page.tags="RenderScriptIntrinsic"
+sample.group=RenderScript
+@jd:body
+
+<p>
+
+ RenderScriptIntrinsic sample that demonstrates how to use RenderScript intrinsics.
+ Creates several RenderScript intrinsics and shows a filtering result with various parameters.
+ Also shows how to extends RedioButton with StateListDrawable.
+
+ </p>
diff --git a/samples/browseable/RenderScriptIntrinsic/res/drawable-hdpi/ic_launcher.png b/samples/browseable/RenderScriptIntrinsic/res/drawable-hdpi/ic_launcher.png
new file mode 100755
index 000000000..75b3c9781
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/RenderScriptIntrinsic/res/drawable-hdpi/tile.9.png b/samples/browseable/RenderScriptIntrinsic/res/drawable-hdpi/tile.9.png
new file mode 100644
index 000000000..135862883
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/RenderScriptIntrinsic/res/drawable-mdpi/ic_launcher.png b/samples/browseable/RenderScriptIntrinsic/res/drawable-mdpi/ic_launcher.png
new file mode 100755
index 000000000..4ccd98e09
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/RenderScriptIntrinsic/res/drawable-nodpi/data.jpg b/samples/browseable/RenderScriptIntrinsic/res/drawable-nodpi/data.jpg
new file mode 100644
index 000000000..48e48e61b
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/res/drawable-nodpi/data.jpg
Binary files differ
diff --git a/samples/browseable/RenderScriptIntrinsic/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/RenderScriptIntrinsic/res/drawable-xhdpi/ic_launcher.png
new file mode 100755
index 000000000..7c5aeed04
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/RenderScriptIntrinsic/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/RenderScriptIntrinsic/res/drawable-xxhdpi/ic_launcher.png
new file mode 100755
index 000000000..3c45f511e
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/RenderScriptIntrinsic/res/layout/activity_main.xml b/samples/browseable/RenderScriptIntrinsic/res/layout/activity_main.xml
new file mode 100755
index 000000000..be1aa49d9
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+ Copyright 2013 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.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <LinearLayout style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/horizontal_page_margin"
+ android:layout_marginRight="@dimen/horizontal_page_margin"
+ android:layout_marginTop="@dimen/vertical_page_margin"
+ android:layout_marginBottom="@dimen/vertical_page_margin"
+ android:text="@string/intro_message" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/RenderScriptIntrinsic/res/layout/main_layout.xml b/samples/browseable/RenderScriptIntrinsic/res/layout/main_layout.xml
new file mode 100644
index 000000000..13516d8c2
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/res/layout/main_layout.xml
@@ -0,0 +1,51 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="#0099cc"
+ tools:context=".MainActivity">
+
+ <ImageView
+ android:id="@+id/imageView"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scaleType="centerCrop"
+ android:src="@drawable/data" />
+
+ <RadioGroup
+ android:id="@+id/radioGroup1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:orientation="horizontal"
+ android:layout_above="@+id/seekBar1"
+ android:layout_marginBottom="8dp">
+
+ <com.example.android.renderscriptintrinsic.ThumbnailRadioButton
+ android:id="@+id/radio0"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:checked="true"
+ android:text="Blur" />
+
+ <com.example.android.renderscriptintrinsic.ThumbnailRadioButton
+ android:id="@+id/radio1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Emboss" />
+
+ <com.example.android.renderscriptintrinsic.ThumbnailRadioButton
+ android:id="@+id/radio2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Hue" />
+ </RadioGroup>
+
+ <SeekBar
+ android:id="@+id/seekBar1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_marginBottom="16dp" />
+
+</RelativeLayout>
diff --git a/samples/browseable/RenderScriptIntrinsic/res/values-sw600dp/template-dimens.xml b/samples/browseable/RenderScriptIntrinsic/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 000000000..22074a2bd
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/RenderScriptIntrinsic/res/values-sw600dp/template-styles.xml b/samples/browseable/RenderScriptIntrinsic/res/values-sw600dp/template-styles.xml
new file mode 100644
index 000000000..03d197418
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceLarge</item>
+ <item name="android:lineSpacingMultiplier">1.2</item>
+ <item name="android:shadowDy">-6.5</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/RenderScriptIntrinsic/res/values-v11/styles.xml b/samples/browseable/RenderScriptIntrinsic/res/values-v11/styles.xml
new file mode 100644
index 000000000..f3a90c687
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/res/values-v11/styles.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!--
+ Base application theme for API 11+. This theme completely replaces
+ AppBaseTheme from res/values/styles.xml on API 11+ devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Holo.Light">
+ <!-- API 11 theme customizations can go here. -->
+ </style>
+
+ <style name="FullscreenTheme" parent="android:Theme.Holo">
+ <item name="android:actionBarStyle">@style/FullscreenActionBarStyle</item>
+ <item name="android:windowActionBarOverlay">true</item>
+ <item name="android:windowBackground">@null</item>
+ <item name="buttonBarStyle">?android:attr/buttonBarStyle</item>
+ <item name="buttonBarButtonStyle">?android:attr/buttonBarButtonStyle</item>
+ </style>
+
+ <style name="FullscreenActionBarStyle" parent="android:Widget.Holo.ActionBar">
+ <item name="android:background">@color/black_overlay</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/RenderScriptIntrinsic/res/values-v14/styles.xml b/samples/browseable/RenderScriptIntrinsic/res/values-v14/styles.xml
new file mode 100644
index 000000000..a91fd0372
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/res/values-v14/styles.xml
@@ -0,0 +1,12 @@
+<resources>
+
+ <!--
+ Base application theme for API 14+. This theme completely replaces
+ AppBaseTheme from BOTH res/values/styles.xml and
+ res/values-v11/styles.xml on API 14+ devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
+ <!-- API 14 theme customizations can go here. -->
+ </style>
+
+</resources>
diff --git a/samples/browseable/RenderScriptIntrinsic/res/values/attrs.xml b/samples/browseable/RenderScriptIntrinsic/res/values/attrs.xml
new file mode 100644
index 000000000..e67df0a37
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/res/values/attrs.xml
@@ -0,0 +1,14 @@
+<resources>
+
+ <!--
+ Declare custom theme attributes that allow changing which styles are
+ used for button bars depending on the API level.
+ ?android:attr/buttonBarStyle is new as of API 11 so this is
+ necessary to support previous API levels.
+ -->
+ <declare-styleable name="ButtonBarContainerTheme">
+ <attr name="buttonBarStyle" format="reference" />
+ <attr name="buttonBarButtonStyle" format="reference" />
+ </declare-styleable>
+
+</resources>
diff --git a/samples/browseable/RenderScriptIntrinsic/res/values/base-strings.xml b/samples/browseable/RenderScriptIntrinsic/res/values/base-strings.xml
new file mode 100644
index 000000000..c8488beed
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/res/values/base-strings.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+ <string name="app_name">RenderScriptIntrinsic</string>
+ <string name="intro_message">
+ <![CDATA[
+
+
+ RenderScriptIntrinsic sample that demonstrates how to use RenderScript intrinsics.
+ Creates several RenderScript intrinsics and shows a filtering result with various parameters.
+ Also shows how to extends RedioButton with StateListDrawable.
+
+
+ ]]>
+ </string>
+</resources>
diff --git a/samples/browseable/RenderScriptIntrinsic/res/values/colors.xml b/samples/browseable/RenderScriptIntrinsic/res/values/colors.xml
new file mode 100644
index 000000000..327c0604c
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/res/values/colors.xml
@@ -0,0 +1,5 @@
+<resources>
+
+ <color name="black_overlay">#66000000</color>
+
+</resources>
diff --git a/samples/browseable/RenderScriptIntrinsic/res/values/styles.xml b/samples/browseable/RenderScriptIntrinsic/res/values/styles.xml
new file mode 100644
index 000000000..12eb93028
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/res/values/styles.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!--
+ Base application theme, dependent on API level. This theme is replaced
+ by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Light">
+ <!--
+ Theme customizations available in newer API levels can go in
+ res/values-vXX/styles.xml, while customizations related to
+ backward-compatibility can go here.
+ -->
+ </style>
+
+ <style name="FullscreenTheme" parent="android:Theme.NoTitleBar">
+ <item name="android:windowContentOverlay">@null</item>
+ <item name="android:windowBackground">@null</item>
+ <item name="buttonBarStyle">@style/ButtonBar</item>
+ <item name="buttonBarButtonStyle">@style/ButtonBarButton</item>
+ </style>
+
+ <style name="ButtonBar">
+ <item name="android:paddingLeft">2dp</item>
+ <item name="android:paddingTop">5dp</item>
+ <item name="android:paddingRight">2dp</item>
+ <item name="android:paddingBottom">0dp</item>
+ <item name="android:background">@android:drawable/bottom_bar</item>
+ </style>
+
+ <style name="ButtonBarButton" />
+
+</resources>
diff --git a/samples/browseable/RenderScriptIntrinsic/res/values/template-dimens.xml b/samples/browseable/RenderScriptIntrinsic/res/values/template-dimens.xml
new file mode 100644
index 000000000..39e710b5c
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/RenderScriptIntrinsic/res/values/template-styles.xml b/samples/browseable/RenderScriptIntrinsic/res/values/template-styles.xml
new file mode 100644
index 000000000..404623e3d
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/Log.java b/samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/Log.java
new file mode 100644
index 000000000..17503c568
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 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.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+ // Grabbing the native values from Android's native logging facilities,
+ // to make for easy migration and interop.
+ public static final int NONE = -1;
+ public static final int VERBOSE = android.util.Log.VERBOSE;
+ public static final int DEBUG = android.util.Log.DEBUG;
+ public static final int INFO = android.util.Log.INFO;
+ public static final int WARN = android.util.Log.WARN;
+ public static final int ERROR = android.util.Log.ERROR;
+ public static final int ASSERT = android.util.Log.ASSERT;
+
+ // Stores the beginning of the LogNode topology.
+ private static LogNode mLogNode;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public static LogNode getLogNode() {
+ return mLogNode;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to.
+ */
+ public static void setLogNode(LogNode node) {
+ mLogNode = node;
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void println(int priority, String tag, String msg, Throwable tr) {
+ if (mLogNode != null) {
+ mLogNode.println(priority, tag, msg, tr);
+ }
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ */
+ public static void println(int priority, String tag, String msg) {
+ println(priority, tag, msg, null);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void v(String tag, String msg, Throwable tr) {
+ println(VERBOSE, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void v(String tag, String msg) {
+ v(tag, msg, null);
+ }
+
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void d(String tag, String msg, Throwable tr) {
+ println(DEBUG, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void d(String tag, String msg) {
+ d(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void i(String tag, String msg, Throwable tr) {
+ println(INFO, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void i(String tag, String msg) {
+ i(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, String msg, Throwable tr) {
+ println(WARN, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void w(String tag, String msg) {
+ w(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, Throwable tr) {
+ w(tag, null, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void e(String tag, String msg, Throwable tr) {
+ println(ERROR, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void e(String tag, String msg) {
+ e(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, String msg, Throwable tr) {
+ println(ASSERT, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void wtf(String tag, String msg) {
+ wtf(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, Throwable tr) {
+ wtf(tag, null, tr);
+ }
+}
diff --git a/samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/LogFragment.java b/samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/LogFragment.java
new file mode 100644
index 000000000..b302acd4b
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 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.
+*/
+/*
+ * Copyright 2013 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.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+ private LogView mLogView;
+ private ScrollView mScrollView;
+
+ public LogFragment() {}
+
+ public View inflateViews() {
+ mScrollView = new ScrollView(getActivity());
+ ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT);
+ mScrollView.setLayoutParams(scrollParams);
+
+ mLogView = new LogView(getActivity());
+ ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+ logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+ mLogView.setLayoutParams(logParams);
+ mLogView.setClickable(true);
+ mLogView.setFocusable(true);
+ mLogView.setTypeface(Typeface.MONOSPACE);
+
+ // Want to set padding as 16 dips, setPadding takes pixels. Hooray math!
+ int paddingDips = 16;
+ double scale = getResources().getDisplayMetrics().density;
+ int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+ mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+ mLogView.setCompoundDrawablePadding(paddingPixels);
+
+ mLogView.setGravity(Gravity.BOTTOM);
+ mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+ mScrollView.addView(mLogView);
+ return mScrollView;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+
+ View result = inflateViews();
+
+ mLogView.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+ }
+ });
+ return result;
+ }
+
+ public LogView getLogView() {
+ return mLogView;
+ }
+} \ No newline at end of file
diff --git a/samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/LogNode.java b/samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/LogNode.java
new file mode 100644
index 000000000..bc37cabc0
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * 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.example.android.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+ /**
+ * Instructs first LogNode in the list to print the log data provided.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/LogView.java b/samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/LogView.java
new file mode 100644
index 000000000..c01542b91
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 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.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+ public LogView(Context context) {
+ super(context);
+ }
+
+ public LogView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public LogView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ /**
+ * Formats the log data and prints it out to the LogView.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+
+
+ String priorityStr = null;
+
+ // For the purposes of this View, we want to print the priority as readable text.
+ switch(priority) {
+ case android.util.Log.VERBOSE:
+ priorityStr = "VERBOSE";
+ break;
+ case android.util.Log.DEBUG:
+ priorityStr = "DEBUG";
+ break;
+ case android.util.Log.INFO:
+ priorityStr = "INFO";
+ break;
+ case android.util.Log.WARN:
+ priorityStr = "WARN";
+ break;
+ case android.util.Log.ERROR:
+ priorityStr = "ERROR";
+ break;
+ case android.util.Log.ASSERT:
+ priorityStr = "ASSERT";
+ break;
+ default:
+ break;
+ }
+
+ // Handily, the Log class has a facility for converting a stack trace into a usable string.
+ String exceptionStr = null;
+ if (tr != null) {
+ exceptionStr = android.util.Log.getStackTraceString(tr);
+ }
+
+ // Take the priority, tag, message, and exception, and concatenate as necessary
+ // into one usable line of text.
+ final StringBuilder outputBuilder = new StringBuilder();
+
+ String delimiter = "\t";
+ appendIfNotNull(outputBuilder, priorityStr, delimiter);
+ appendIfNotNull(outputBuilder, tag, delimiter);
+ appendIfNotNull(outputBuilder, msg, delimiter);
+ appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+ // In case this was originally called from an AsyncTask or some other off-UI thread,
+ // make sure the update occurs within the UI thread.
+ ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+ @Override
+ public void run() {
+ // Display the text we just generated within the LogView.
+ appendToLog(outputBuilder.toString());
+ }
+ })));
+
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+ * the logger takes so many arguments that might be null, this method helps cut out some of the
+ * agonizing tedium of writing the same 3 lines over and over.
+ * @param source StringBuilder containing the text to append to.
+ * @param addStr The String to append
+ * @param delimiter The String to separate the source and appended strings. A tab or comma,
+ * for instance.
+ * @return The fully concatenated String as a StringBuilder
+ */
+ private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+ if (addStr != null) {
+ if (addStr.length() == 0) {
+ delimiter = "";
+ }
+
+ return source.append(addStr).append(delimiter);
+ }
+ return source;
+ }
+
+ // The next LogNode in the chain.
+ LogNode mNext;
+
+ /** Outputs the string as a new line of log data in the LogView. */
+ public void appendToLog(String s) {
+ append("\n" + s);
+ }
+
+
+}
diff --git a/samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/LogWrapper.java b/samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/LogWrapper.java
new file mode 100644
index 000000000..16a9e7ba2
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * 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.example.android.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface. This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+ // For piping: The next node to receive Log data after this one has done its work.
+ private LogNode mNext;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /**
+ * Prints data out to the console using Android's native log mechanism.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ // There actually are log methods that don't take a msg parameter. For now,
+ // if that's the case, just convert null to the empty string and move on.
+ String useMsg = msg;
+ if (useMsg == null) {
+ useMsg = "";
+ }
+
+ // If an exeption was provided, convert that exception to a usable string and attach
+ // it to the end of the msg method.
+ if (tr != null) {
+ msg += "\n" + Log.getStackTraceString(tr);
+ }
+
+ // This is functionally identical to Log.x(tag, useMsg);
+ // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+ Log.println(priority, tag, useMsg);
+
+ // If this isn't the last node in the chain, move things along.
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+}
diff --git a/samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/MessageOnlyLogFilter.java b/samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/MessageOnlyLogFilter.java
new file mode 100644
index 000000000..19967dcd4
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 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.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+ LogNode mNext;
+
+ /**
+ * Takes the "next" LogNode as a parameter, to simplify chaining.
+ *
+ * @param next The next LogNode in the pipeline.
+ */
+ public MessageOnlyLogFilter(LogNode next) {
+ mNext = next;
+ }
+
+ public MessageOnlyLogFilter() {
+ }
+
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ if (mNext != null) {
+ getNext().println(Log.NONE, null, msg, null);
+ }
+ }
+
+ /**
+ * Returns the next LogNode in the chain.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+}
diff --git a/samples/browseable/RenderScriptIntrinsic/src/com.example.android.renderscriptintrinsic/MainActivity.java b/samples/browseable/RenderScriptIntrinsic/src/com.example.android.renderscriptintrinsic/MainActivity.java
new file mode 100644
index 000000000..4b6f5ce16
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/src/com.example.android.renderscriptintrinsic/MainActivity.java
@@ -0,0 +1,370 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.renderscriptintrinsic;
+
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.ImageView;
+import android.widget.RadioButton;
+import android.widget.SeekBar;
+import android.widget.SeekBar.OnSeekBarChangeListener;
+import android.support.v8.renderscript.*;
+
+public class MainActivity extends Activity {
+ /* Number of bitmaps that is used for renderScript thread and UI thread synchronization.
+ Ideally, this can be reduced to 2, however in some devices, 2 buffers still showing tierings on UI.
+ Investigating a root cause.
+ */
+ private final int NUM_BITMAPS = 3;
+ private int mCurrentBitmap = 0;
+ private Bitmap mBitmapIn;
+ private Bitmap[] mBitmapsOut;
+ private ImageView mImageView;
+
+ private RenderScript mRS;
+ private Allocation mInAllocation;
+ private Allocation[] mOutAllocations;
+
+ private ScriptIntrinsicBlur mScriptBlur;
+ private ScriptIntrinsicConvolve5x5 mScriptConvolve;
+ private ScriptIntrinsicColorMatrix mScriptMatrix;
+
+ private final int MODE_BLUR = 0;
+ private final int MODE_CONVOLVE = 1;
+ private final int MODE_COLORMATRIX = 2;
+
+ private int mFilterMode = MODE_BLUR;
+
+ private RenderScriptTask mLatestTask = null;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.main_layout);
+
+ /*
+ * Initialize UI
+ */
+
+ //Set up main image view
+ mBitmapIn = loadBitmap(R.drawable.data);
+ mBitmapsOut = new Bitmap[NUM_BITMAPS];
+ for (int i = 0; i < NUM_BITMAPS; ++i) {
+ mBitmapsOut[i] = Bitmap.createBitmap(mBitmapIn.getWidth(),
+ mBitmapIn.getHeight(), mBitmapIn.getConfig());
+ }
+
+ mImageView = (ImageView) findViewById(R.id.imageView);
+ mImageView.setImageBitmap(mBitmapsOut[mCurrentBitmap]);
+ mCurrentBitmap += (mCurrentBitmap + 1) % NUM_BITMAPS;
+
+ //Set up seekbar
+ final SeekBar seekbar = (SeekBar) findViewById(R.id.seekBar1);
+ seekbar.setProgress(50);
+ seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
+ public void onProgressChanged(SeekBar seekBar, int progress,
+ boolean fromUser) {
+ updateImage(progress);
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ }
+ });
+
+ //Setup effect selector
+ RadioButton radio0 = (RadioButton) findViewById(R.id.radio0);
+ radio0.setOnCheckedChangeListener(new OnCheckedChangeListener() {
+
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (isChecked) {
+ mFilterMode = MODE_BLUR;
+ updateImage(seekbar.getProgress());
+ }
+ }
+ });
+ RadioButton radio1 = (RadioButton) findViewById(R.id.radio1);
+ radio1.setOnCheckedChangeListener(new OnCheckedChangeListener() {
+
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (isChecked) {
+ mFilterMode = MODE_CONVOLVE;
+ updateImage(seekbar.getProgress());
+ }
+ }
+ });
+ RadioButton radio2 = (RadioButton) findViewById(R.id.radio2);
+ radio2.setOnCheckedChangeListener(new OnCheckedChangeListener() {
+
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (isChecked) {
+ mFilterMode = MODE_COLORMATRIX;
+ updateImage(seekbar.getProgress());
+ }
+ }
+ });
+
+ /*
+ * Create renderScript
+ */
+ createScript();
+
+ /*
+ * Create thumbnails
+ */
+ createThumbnail();
+
+
+ /*
+ * Invoke renderScript kernel and update imageView
+ */
+ mFilterMode = MODE_BLUR;
+ updateImage(50);
+ }
+
+ private void createScript() {
+ mRS = RenderScript.create(this);
+
+ mInAllocation = Allocation.createFromBitmap(mRS, mBitmapIn);
+
+ mOutAllocations = new Allocation[NUM_BITMAPS];
+ for (int i = 0; i < NUM_BITMAPS; ++i) {
+ mOutAllocations[i] = Allocation.createFromBitmap(mRS, mBitmapsOut[i]);
+ }
+
+ /*
+ Create intrinsics.
+ RenderScript has built-in features such as blur, convolve filter etc.
+ These intrinsics are handy for specific operations without writing RenderScript kernel.
+ In the sample, it's creating blur, convolve and matrix intrinsics.
+ */
+
+ mScriptBlur = ScriptIntrinsicBlur.create(mRS, Element.U8_4(mRS));
+ mScriptConvolve = ScriptIntrinsicConvolve5x5.create(mRS,
+ Element.U8_4(mRS));
+ mScriptMatrix = ScriptIntrinsicColorMatrix.create(mRS,
+ Element.U8_4(mRS));
+ }
+
+ private void performFilter(Allocation inAllocation,
+ Allocation outAllocation, Bitmap bitmapOut, float value) {
+ switch (mFilterMode) {
+ case MODE_BLUR:
+ /*
+ * Set blur kernel size
+ */
+ mScriptBlur.setRadius(value);
+
+ /*
+ * Invoke filter kernel
+ */
+ mScriptBlur.setInput(inAllocation);
+ mScriptBlur.forEach(outAllocation);
+ break;
+ case MODE_CONVOLVE: {
+ float f1 = value;
+ float f2 = 1.0f - f1;
+
+ // Emboss filter kernel
+ float coefficients[] = {-f1 * 2, 0, -f1, 0, 0, 0, -f2 * 2, -f2, 0,
+ 0, -f1, -f2, 1, f2, f1, 0, 0, f2, f2 * 2, 0, 0, 0, f1, 0,
+ f1 * 2,};
+ /*
+ * Set kernel parameter
+ */
+ mScriptConvolve.setCoefficients(coefficients);
+
+ /*
+ * Invoke filter kernel
+ */
+ mScriptConvolve.setInput(inAllocation);
+ mScriptConvolve.forEach(outAllocation);
+ break;
+ }
+ case MODE_COLORMATRIX: {
+ /*
+ * Set HUE rotation matrix
+ * The matrix below performs a combined operation of,
+ * RGB->HSV transform * HUE rotation * HSV->RGB transform
+ */
+ float cos = (float) Math.cos((double) value);
+ float sin = (float) Math.sin((double) value);
+ Matrix3f mat = new Matrix3f();
+ mat.set(0, 0, (float) (.299 + .701 * cos + .168 * sin));
+ mat.set(1, 0, (float) (.587 - .587 * cos + .330 * sin));
+ mat.set(2, 0, (float) (.114 - .114 * cos - .497 * sin));
+ mat.set(0, 1, (float) (.299 - .299 * cos - .328 * sin));
+ mat.set(1, 1, (float) (.587 + .413 * cos + .035 * sin));
+ mat.set(2, 1, (float) (.114 - .114 * cos + .292 * sin));
+ mat.set(0, 2, (float) (.299 - .3 * cos + 1.25 * sin));
+ mat.set(1, 2, (float) (.587 - .588 * cos - 1.05 * sin));
+ mat.set(2, 2, (float) (.114 + .886 * cos - .203 * sin));
+ mScriptMatrix.setColorMatrix(mat);
+
+ /*
+ * Invoke filter kernel
+ */
+ mScriptMatrix.forEach(inAllocation, outAllocation);
+ }
+ break;
+ }
+
+ /*
+ * Copy to bitmap and invalidate image view
+ */
+ outAllocation.copyTo(bitmapOut);
+ }
+
+ /*
+ Convert seekBar progress parameter (0-100 in range) to parameter for each intrinsic filter.
+ (e.g. 1.0-25.0 in Blur filter)
+ */
+ private float getFilterParameter(int i) {
+ float f = 0.f;
+ switch (mFilterMode) {
+ case MODE_BLUR: {
+ final float max = 25.0f;
+ final float min = 1.f;
+ f = (float) ((max - min) * (i / 100.0) + min);
+ }
+ break;
+ case MODE_CONVOLVE: {
+ final float max = 2.f;
+ final float min = 0.f;
+ f = (float) ((max - min) * (i / 100.0) + min);
+ }
+ break;
+ case MODE_COLORMATRIX: {
+ final float max = (float) Math.PI;
+ final float min = (float) -Math.PI;
+ f = (float) ((max - min) * (i / 100.0) + min);
+ }
+ break;
+ }
+ return f;
+
+ }
+
+ /*
+ * In the AsyncTask, it invokes RenderScript intrinsics to do a filtering.
+ * After the filtering is done, an operation blocks at Allication.copyTo() in AsyncTask thread.
+ * Once all operation is finished at onPostExecute() in UI thread, it can invalidate and update ImageView UI.
+ */
+ private class RenderScriptTask extends AsyncTask<Float, Integer, Integer> {
+ Boolean issued = false;
+
+ protected Integer doInBackground(Float... values) {
+ int index = -1;
+ if (isCancelled() == false) {
+ issued = true;
+ index = mCurrentBitmap;
+
+ performFilter(mInAllocation, mOutAllocations[index], mBitmapsOut[index], values[0]);
+ mCurrentBitmap = (mCurrentBitmap + 1) % NUM_BITMAPS;
+ }
+ return index;
+ }
+
+ void updateView(Integer result) {
+ if (result != -1) {
+ // Request UI update
+ mImageView.setImageBitmap(mBitmapsOut[result]);
+ mImageView.invalidate();
+ }
+ }
+
+ protected void onPostExecute(Integer result) {
+ updateView(result);
+ }
+
+ protected void onCancelled(Integer result) {
+ if (issued) {
+ updateView(result);
+ }
+ }
+ }
+
+ /*
+ Invoke AsynchTask and cancel previous task.
+ When AsyncTasks are piled up (typically in slow device with heavy kernel),
+ Only the latest (and already started) task invokes RenderScript operation.
+ */
+ private void updateImage(int progress) {
+ float f = getFilterParameter(progress);
+
+ if (mLatestTask != null)
+ mLatestTask.cancel(false);
+ mLatestTask = new RenderScriptTask();
+
+ mLatestTask.execute(f);
+ }
+
+ /*
+ Helper to load Bitmap from resource
+ */
+ private Bitmap loadBitmap(int resource) {
+ final BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inPreferredConfig = Bitmap.Config.ARGB_8888;
+ return BitmapFactory.decodeResource(getResources(), resource, options);
+ }
+
+ /*
+ Create thumbNail for UI. It invokes RenderScript kernel synchronously in UI-thread,
+ which is OK for small thumbnail (but not ideal).
+ */
+ private void createThumbnail() {
+ int width = 72;
+ int height = 96;
+ float scale = getResources().getDisplayMetrics().density;
+ int pixelsWidth = (int) (width * scale + 0.5f);
+ int pixelsHeight = (int) (height * scale + 0.5f);
+
+ //Temporary image
+ Bitmap tempBitmap = Bitmap.createScaledBitmap(mBitmapIn, pixelsWidth, pixelsHeight, false);
+ Allocation inAllocation = Allocation.createFromBitmap(mRS, tempBitmap);
+
+ //Create thumbnail with each RS intrinsic and set it to radio buttons
+ int[] modes = {MODE_BLUR, MODE_CONVOLVE, MODE_COLORMATRIX};
+ int[] ids = {R.id.radio0, R.id.radio1, R.id.radio2};
+ int[] parameter = {50, 100, 25};
+ for (int mode : modes) {
+ mFilterMode = mode;
+ float f = getFilterParameter(parameter[mode]);
+
+ Bitmap destBitpmap = Bitmap.createBitmap(tempBitmap.getWidth(),
+ tempBitmap.getHeight(), tempBitmap.getConfig());
+ Allocation outAllocation = Allocation.createFromBitmap(mRS, destBitpmap);
+ performFilter(inAllocation, outAllocation, destBitpmap, f);
+
+ ThumbnailRadioButton button = (ThumbnailRadioButton) findViewById(ids[mode]);
+ button.setThumbnail(destBitpmap);
+ }
+ }
+}
diff --git a/samples/browseable/RenderScriptIntrinsic/src/com.example.android.renderscriptintrinsic/ThumbnailRadioButton.java b/samples/browseable/RenderScriptIntrinsic/src/com.example.android.renderscriptintrinsic/ThumbnailRadioButton.java
new file mode 100644
index 000000000..160e970b6
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/src/com.example.android.renderscriptintrinsic/ThumbnailRadioButton.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.renderscriptintrinsic;
+
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.graphics.drawable.ShapeDrawable;
+import android.graphics.drawable.StateListDrawable;
+import android.graphics.drawable.shapes.RectShape;
+import android.os.Build;
+import android.view.Gravity;
+import android.widget.RadioButton;
+import android.content.Context;
+import android.util.AttributeSet;
+
+/*
+ A button with Thumbnail which extends Radio Button.
+ The widget override a background drawable of Radio Button with a StateList Drawable.
+ Each state has a LayerDrawable with a Thumbnail image and a Focus rectangle.
+ It's using original Radio Buttons text as a label, because LayerDrawable showed some issues with Canvas.drawText().
+ */
+public class ThumbnailRadioButton extends RadioButton {
+ public ThumbnailRadioButton(Context context) {
+ super(context);
+ init();
+ }
+
+ public ThumbnailRadioButton(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ public ThumbnailRadioButton(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init();
+ }
+
+ private void init() {
+ setButtonDrawable(android.R.color.transparent);
+ }
+
+ public void setThumbnail(Bitmap bitmap) {
+ //Bitmap drawable
+ BitmapDrawable bmp = new BitmapDrawable(getResources(), bitmap);
+ bmp.setGravity(Gravity.CENTER);
+
+ int strokeWidth = 24;
+ //Checked state
+ ShapeDrawable rectChecked = new ShapeDrawable(new RectShape());
+ rectChecked.getPaint().setColor(0xFFFFFFFF);
+ rectChecked.getPaint().setStyle(Paint.Style.STROKE);
+ rectChecked.getPaint().setStrokeWidth(strokeWidth);
+ rectChecked.setIntrinsicWidth(bitmap.getWidth() + strokeWidth);
+ rectChecked.setIntrinsicHeight(bitmap.getHeight() + strokeWidth);
+ Drawable drawableArray[] = new Drawable[]{bmp, rectChecked};
+ LayerDrawable layerChecked = new LayerDrawable(drawableArray);
+
+ //Unchecked state
+ ShapeDrawable rectUnchecked = new ShapeDrawable(new RectShape());
+ rectUnchecked.getPaint().setColor(0x0);
+ rectUnchecked.getPaint().setStyle(Paint.Style.STROKE);
+ rectUnchecked.getPaint().setStrokeWidth(strokeWidth);
+ rectUnchecked.setIntrinsicWidth(bitmap.getWidth() + strokeWidth);
+ rectUnchecked.setIntrinsicHeight(bitmap.getHeight() + strokeWidth);
+ Drawable drawableArray2[] = new Drawable[]{bmp, rectUnchecked};
+ LayerDrawable layerUnchecked = new LayerDrawable(drawableArray2);
+
+ //Statelist drawable
+ StateListDrawable states = new StateListDrawable();
+ states.addState(new int[]{android.R.attr.state_checked},
+ layerChecked);
+ states.addState(new int[]{},
+ layerUnchecked);
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
+ setBackground(states);
+ else
+ setBackgroundDrawable(states);
+
+ //Offset text to center/bottom of the checkbox
+ Paint paint = new Paint();
+ paint.setAntiAlias(true);
+ paint.setTextSize(getTextSize());
+ paint.setTypeface(getTypeface());
+ float w = paint.measureText(getText(), 0, getText().length());
+ setPadding(getPaddingLeft() + (int) ((bitmap.getWidth() - w) / 2.f + .5f),
+ getPaddingTop() + (int) (bitmap.getHeight() * 0.70),
+ getPaddingRight(),
+ getPaddingBottom());
+
+ setShadowLayer(5, 0, 0, Color.BLACK);
+ }
+}
diff --git a/samples/browseable/repeatingAlarm/AndroidManifest.xml b/samples/browseable/RepeatingAlarm/AndroidManifest.xml
index b7d02e570..b7d02e570 100644
--- a/samples/browseable/repeatingAlarm/AndroidManifest.xml
+++ b/samples/browseable/RepeatingAlarm/AndroidManifest.xml
diff --git a/samples/browseable/RepeatingAlarm/_index.jd b/samples/browseable/RepeatingAlarm/_index.jd
new file mode 100644
index 000000000..85e1dda5f
--- /dev/null
+++ b/samples/browseable/RepeatingAlarm/_index.jd
@@ -0,0 +1,13 @@
+
+
+
+page.tags="RepeatingAlarm"
+sample.group=Background
+@jd:body
+
+<p>
+
+ Introductory text that explains what the sample is intended to demonstrate. Edit
+ in template-params.xml.
+
+ </p>
diff --git a/samples/browseable/repeatingAlarm/res/drawable-hdpi/ic_launcher.png b/samples/browseable/RepeatingAlarm/res/drawable-hdpi/ic_launcher.png
index b1efaf4b2..b1efaf4b2 100644
--- a/samples/browseable/repeatingAlarm/res/drawable-hdpi/ic_launcher.png
+++ b/samples/browseable/RepeatingAlarm/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/RepeatingAlarm/res/drawable-hdpi/tile.9.png b/samples/browseable/RepeatingAlarm/res/drawable-hdpi/tile.9.png
new file mode 100644
index 000000000..135862883
--- /dev/null
+++ b/samples/browseable/RepeatingAlarm/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/repeatingAlarm/res/drawable-mdpi/ic_launcher.png b/samples/browseable/RepeatingAlarm/res/drawable-mdpi/ic_launcher.png
index f5f9244f2..f5f9244f2 100644
--- a/samples/browseable/repeatingAlarm/res/drawable-mdpi/ic_launcher.png
+++ b/samples/browseable/RepeatingAlarm/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/repeatingAlarm/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/RepeatingAlarm/res/drawable-xhdpi/ic_launcher.png
index 5d07b3f06..5d07b3f06 100644
--- a/samples/browseable/repeatingAlarm/res/drawable-xhdpi/ic_launcher.png
+++ b/samples/browseable/RepeatingAlarm/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/repeatingAlarm/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/RepeatingAlarm/res/drawable-xxhdpi/ic_launcher.png
index 6ef21e1f4..6ef21e1f4 100644
--- a/samples/browseable/repeatingAlarm/res/drawable-xxhdpi/ic_launcher.png
+++ b/samples/browseable/RepeatingAlarm/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/repeatingAlarm/res/layout/activity_main.xml b/samples/browseable/RepeatingAlarm/res/layout/activity_main.xml
index bc5a57591..bc5a57591 100755
--- a/samples/browseable/repeatingAlarm/res/layout/activity_main.xml
+++ b/samples/browseable/RepeatingAlarm/res/layout/activity_main.xml
diff --git a/samples/browseable/repeatingAlarm/res/menu/main.xml b/samples/browseable/RepeatingAlarm/res/menu/main.xml
index 2c3515dd4..2c3515dd4 100644
--- a/samples/browseable/repeatingAlarm/res/menu/main.xml
+++ b/samples/browseable/RepeatingAlarm/res/menu/main.xml
diff --git a/samples/browseable/RepeatingAlarm/res/values-sw600dp/template-dimens.xml b/samples/browseable/RepeatingAlarm/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 000000000..22074a2bd
--- /dev/null
+++ b/samples/browseable/RepeatingAlarm/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/RepeatingAlarm/res/values-sw600dp/template-styles.xml b/samples/browseable/RepeatingAlarm/res/values-sw600dp/template-styles.xml
new file mode 100644
index 000000000..03d197418
--- /dev/null
+++ b/samples/browseable/RepeatingAlarm/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceLarge</item>
+ <item name="android:lineSpacingMultiplier">1.2</item>
+ <item name="android:shadowDy">-6.5</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/repeatingAlarm/res/values/base-strings.xml b/samples/browseable/RepeatingAlarm/res/values/base-strings.xml
index c11b89b86..6b89192f6 100644
--- a/samples/browseable/repeatingAlarm/res/values/base-strings.xml
+++ b/samples/browseable/RepeatingAlarm/res/values/base-strings.xml
@@ -18,7 +18,7 @@
<resources>
- <string name="app_name">repeatingAlarm</string>
+ <string name="app_name">RepeatingAlarm</string>
<string name="intro_message">
<![CDATA[
diff --git a/samples/browseable/repeatingAlarm/res/values/strings.xml b/samples/browseable/RepeatingAlarm/res/values/strings.xml
index 2013d95c1..2013d95c1 100644
--- a/samples/browseable/repeatingAlarm/res/values/strings.xml
+++ b/samples/browseable/RepeatingAlarm/res/values/strings.xml
diff --git a/samples/browseable/RepeatingAlarm/res/values/template-dimens.xml b/samples/browseable/RepeatingAlarm/res/values/template-dimens.xml
new file mode 100644
index 000000000..39e710b5c
--- /dev/null
+++ b/samples/browseable/RepeatingAlarm/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/ImmersiveMode/res/values/styles.xml b/samples/browseable/RepeatingAlarm/res/values/template-styles.xml
index d3f82ff64..d3f82ff64 100644
--- a/samples/browseable/ImmersiveMode/res/values/styles.xml
+++ b/samples/browseable/RepeatingAlarm/res/values/template-styles.xml
diff --git a/samples/browseable/RepeatingAlarm/src/com.example.android.common/activities/SampleActivityBase.java b/samples/browseable/RepeatingAlarm/src/com.example.android.common/activities/SampleActivityBase.java
new file mode 100644
index 000000000..3228927b7
--- /dev/null
+++ b/samples/browseable/RepeatingAlarm/src/com.example.android.common/activities/SampleActivityBase.java
@@ -0,0 +1,52 @@
+/*
+* Copyright 2013 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.example.android.common.activities;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogWrapper;
+
+/**
+ * Base launcher activity, to handle most of the common plumbing for samples.
+ */
+public class SampleActivityBase extends FragmentActivity {
+
+ public static final String TAG = "SampleActivityBase";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ initializeLogging();
+ }
+
+ /** Set up targets to receive log data */
+ public void initializeLogging() {
+ // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+ // Wraps Android's native log framework
+ LogWrapper logWrapper = new LogWrapper();
+ Log.setLogNode(logWrapper);
+
+ Log.i(TAG, "Ready");
+ }
+}
diff --git a/samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/Log.java b/samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/Log.java
new file mode 100644
index 000000000..17503c568
--- /dev/null
+++ b/samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 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.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+ // Grabbing the native values from Android's native logging facilities,
+ // to make for easy migration and interop.
+ public static final int NONE = -1;
+ public static final int VERBOSE = android.util.Log.VERBOSE;
+ public static final int DEBUG = android.util.Log.DEBUG;
+ public static final int INFO = android.util.Log.INFO;
+ public static final int WARN = android.util.Log.WARN;
+ public static final int ERROR = android.util.Log.ERROR;
+ public static final int ASSERT = android.util.Log.ASSERT;
+
+ // Stores the beginning of the LogNode topology.
+ private static LogNode mLogNode;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public static LogNode getLogNode() {
+ return mLogNode;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to.
+ */
+ public static void setLogNode(LogNode node) {
+ mLogNode = node;
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void println(int priority, String tag, String msg, Throwable tr) {
+ if (mLogNode != null) {
+ mLogNode.println(priority, tag, msg, tr);
+ }
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ */
+ public static void println(int priority, String tag, String msg) {
+ println(priority, tag, msg, null);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void v(String tag, String msg, Throwable tr) {
+ println(VERBOSE, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void v(String tag, String msg) {
+ v(tag, msg, null);
+ }
+
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void d(String tag, String msg, Throwable tr) {
+ println(DEBUG, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void d(String tag, String msg) {
+ d(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void i(String tag, String msg, Throwable tr) {
+ println(INFO, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void i(String tag, String msg) {
+ i(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, String msg, Throwable tr) {
+ println(WARN, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void w(String tag, String msg) {
+ w(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, Throwable tr) {
+ w(tag, null, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void e(String tag, String msg, Throwable tr) {
+ println(ERROR, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void e(String tag, String msg) {
+ e(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, String msg, Throwable tr) {
+ println(ASSERT, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void wtf(String tag, String msg) {
+ wtf(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, Throwable tr) {
+ wtf(tag, null, tr);
+ }
+}
diff --git a/samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/LogFragment.java
new file mode 100644
index 000000000..b302acd4b
--- /dev/null
+++ b/samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 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.
+*/
+/*
+ * Copyright 2013 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.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+ private LogView mLogView;
+ private ScrollView mScrollView;
+
+ public LogFragment() {}
+
+ public View inflateViews() {
+ mScrollView = new ScrollView(getActivity());
+ ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT);
+ mScrollView.setLayoutParams(scrollParams);
+
+ mLogView = new LogView(getActivity());
+ ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+ logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+ mLogView.setLayoutParams(logParams);
+ mLogView.setClickable(true);
+ mLogView.setFocusable(true);
+ mLogView.setTypeface(Typeface.MONOSPACE);
+
+ // Want to set padding as 16 dips, setPadding takes pixels. Hooray math!
+ int paddingDips = 16;
+ double scale = getResources().getDisplayMetrics().density;
+ int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+ mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+ mLogView.setCompoundDrawablePadding(paddingPixels);
+
+ mLogView.setGravity(Gravity.BOTTOM);
+ mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+ mScrollView.addView(mLogView);
+ return mScrollView;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+
+ View result = inflateViews();
+
+ mLogView.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+ }
+ });
+ return result;
+ }
+
+ public LogView getLogView() {
+ return mLogView;
+ }
+} \ No newline at end of file
diff --git a/samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/LogNode.java b/samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/LogNode.java
new file mode 100644
index 000000000..bc37cabc0
--- /dev/null
+++ b/samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * 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.example.android.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+ /**
+ * Instructs first LogNode in the list to print the log data provided.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/LogView.java b/samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/LogView.java
new file mode 100644
index 000000000..c01542b91
--- /dev/null
+++ b/samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 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.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+ public LogView(Context context) {
+ super(context);
+ }
+
+ public LogView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public LogView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ /**
+ * Formats the log data and prints it out to the LogView.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+
+
+ String priorityStr = null;
+
+ // For the purposes of this View, we want to print the priority as readable text.
+ switch(priority) {
+ case android.util.Log.VERBOSE:
+ priorityStr = "VERBOSE";
+ break;
+ case android.util.Log.DEBUG:
+ priorityStr = "DEBUG";
+ break;
+ case android.util.Log.INFO:
+ priorityStr = "INFO";
+ break;
+ case android.util.Log.WARN:
+ priorityStr = "WARN";
+ break;
+ case android.util.Log.ERROR:
+ priorityStr = "ERROR";
+ break;
+ case android.util.Log.ASSERT:
+ priorityStr = "ASSERT";
+ break;
+ default:
+ break;
+ }
+
+ // Handily, the Log class has a facility for converting a stack trace into a usable string.
+ String exceptionStr = null;
+ if (tr != null) {
+ exceptionStr = android.util.Log.getStackTraceString(tr);
+ }
+
+ // Take the priority, tag, message, and exception, and concatenate as necessary
+ // into one usable line of text.
+ final StringBuilder outputBuilder = new StringBuilder();
+
+ String delimiter = "\t";
+ appendIfNotNull(outputBuilder, priorityStr, delimiter);
+ appendIfNotNull(outputBuilder, tag, delimiter);
+ appendIfNotNull(outputBuilder, msg, delimiter);
+ appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+ // In case this was originally called from an AsyncTask or some other off-UI thread,
+ // make sure the update occurs within the UI thread.
+ ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+ @Override
+ public void run() {
+ // Display the text we just generated within the LogView.
+ appendToLog(outputBuilder.toString());
+ }
+ })));
+
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+ * the logger takes so many arguments that might be null, this method helps cut out some of the
+ * agonizing tedium of writing the same 3 lines over and over.
+ * @param source StringBuilder containing the text to append to.
+ * @param addStr The String to append
+ * @param delimiter The String to separate the source and appended strings. A tab or comma,
+ * for instance.
+ * @return The fully concatenated String as a StringBuilder
+ */
+ private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+ if (addStr != null) {
+ if (addStr.length() == 0) {
+ delimiter = "";
+ }
+
+ return source.append(addStr).append(delimiter);
+ }
+ return source;
+ }
+
+ // The next LogNode in the chain.
+ LogNode mNext;
+
+ /** Outputs the string as a new line of log data in the LogView. */
+ public void appendToLog(String s) {
+ append("\n" + s);
+ }
+
+
+}
diff --git a/samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/LogWrapper.java
new file mode 100644
index 000000000..16a9e7ba2
--- /dev/null
+++ b/samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * 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.example.android.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface. This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+ // For piping: The next node to receive Log data after this one has done its work.
+ private LogNode mNext;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /**
+ * Prints data out to the console using Android's native log mechanism.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ // There actually are log methods that don't take a msg parameter. For now,
+ // if that's the case, just convert null to the empty string and move on.
+ String useMsg = msg;
+ if (useMsg == null) {
+ useMsg = "";
+ }
+
+ // If an exeption was provided, convert that exception to a usable string and attach
+ // it to the end of the msg method.
+ if (tr != null) {
+ msg += "\n" + Log.getStackTraceString(tr);
+ }
+
+ // This is functionally identical to Log.x(tag, useMsg);
+ // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+ Log.println(priority, tag, useMsg);
+
+ // If this isn't the last node in the chain, move things along.
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+}
diff --git a/samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java
new file mode 100644
index 000000000..19967dcd4
--- /dev/null
+++ b/samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 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.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+ LogNode mNext;
+
+ /**
+ * Takes the "next" LogNode as a parameter, to simplify chaining.
+ *
+ * @param next The next LogNode in the pipeline.
+ */
+ public MessageOnlyLogFilter(LogNode next) {
+ mNext = next;
+ }
+
+ public MessageOnlyLogFilter() {
+ }
+
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ if (mNext != null) {
+ getNext().println(Log.NONE, null, msg, null);
+ }
+ }
+
+ /**
+ * Returns the next LogNode in the chain.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+}
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.repeatingalarm/MainActivity.java b/samples/browseable/RepeatingAlarm/src/com.example.android.repeatingalarm/MainActivity.java
index 2d2a6aaad..2d2a6aaad 100644
--- a/samples/browseable/repeatingAlarm/src/com.example.android.repeatingalarm/MainActivity.java
+++ b/samples/browseable/RepeatingAlarm/src/com.example.android.repeatingalarm/MainActivity.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.repeatingalarm/RepeatingAlarmFragment.java b/samples/browseable/RepeatingAlarm/src/com.example.android.repeatingalarm/RepeatingAlarmFragment.java
index 81b1e447f..81b1e447f 100644
--- a/samples/browseable/repeatingAlarm/src/com.example.android.repeatingalarm/RepeatingAlarmFragment.java
+++ b/samples/browseable/RepeatingAlarm/src/com.example.android.repeatingalarm/RepeatingAlarmFragment.java
diff --git a/samples/browseable/SlidingTabsBasic/AndroidManifest.xml b/samples/browseable/SlidingTabsBasic/AndroidManifest.xml
new file mode 100644
index 000000000..31cbfb893
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/AndroidManifest.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 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.
+-->
+
+
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.slidingtabsbasic"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="19" />
+
+ <application android:allowBackup="true"
+ android:label="@string/app_name"
+ android:icon="@drawable/ic_launcher"
+ android:theme="@style/AppTheme">
+
+ <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>
+ </application>
+
+
+</manifest>
diff --git a/samples/browseable/SlidingTabsBasic/_index.jd b/samples/browseable/SlidingTabsBasic/_index.jd
new file mode 100644
index 000000000..60610d225
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/_index.jd
@@ -0,0 +1,13 @@
+
+
+
+page.tags="SlidingTabsBasic"
+sample.group=UI
+@jd:body
+
+<p>
+
+ A basic sample which shows how to use SlidingTabLayout to display a custom
+ ViewPager title strip which gives continuous feedback to the user when scrolling.
+
+ </p>
diff --git a/samples/browseable/SlidingTabsBasic/res/drawable-hdpi/ic_launcher.png b/samples/browseable/SlidingTabsBasic/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 000000000..53ebb5772
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/SlidingTabsBasic/res/drawable-hdpi/tile.9.png b/samples/browseable/SlidingTabsBasic/res/drawable-hdpi/tile.9.png
new file mode 100644
index 000000000..135862883
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/SlidingTabsBasic/res/drawable-mdpi/ic_launcher.png b/samples/browseable/SlidingTabsBasic/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 000000000..33aa87a64
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/SlidingTabsBasic/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/SlidingTabsBasic/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..6a4ba0004
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/SlidingTabsBasic/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/SlidingTabsBasic/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..c3744cd0f
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/SlidingTabsBasic/res/layout-w720dp/activity_main.xml b/samples/browseable/SlidingTabsBasic/res/layout-w720dp/activity_main.xml
new file mode 100755
index 000000000..c9a52f621
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/res/layout-w720dp/activity_main.xml
@@ -0,0 +1,73 @@
+<!--
+ Copyright 2013 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.
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/sample_main_layout">
+
+ <LinearLayout
+ android:id="@+id/sample_output"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:orientation="vertical">
+
+ <FrameLayout
+ style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/margin_medium"
+ android:paddingRight="@dimen/margin_medium"
+ android:paddingTop="@dimen/margin_large"
+ android:paddingBottom="@dimen/margin_large"
+ android:text="@string/intro_message" />
+ </FrameLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@android:color/darker_gray" />
+
+ <fragment
+ android:name="com.example.android.common.logger.LogFragment"
+ android:id="@+id/log_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1" />
+
+ </LinearLayout>
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:background="@android:color/darker_gray" />
+
+ <FrameLayout
+ android:id="@+id/sample_content_fragment"
+ android:layout_weight="2"
+ android:layout_width="0px"
+ android:layout_height="match_parent" />
+
+</LinearLayout>
+
+
diff --git a/samples/browseable/SlidingTabsBasic/res/layout/activity_main.xml b/samples/browseable/SlidingTabsBasic/res/layout/activity_main.xml
new file mode 100755
index 000000000..1ae4f981e
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/res/layout/activity_main.xml
@@ -0,0 +1,65 @@
+<!--
+ Copyright 2013 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.
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/sample_main_layout">
+
+ <ViewAnimator
+ android:id="@+id/sample_output"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1">
+
+ <ScrollView
+ style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/horizontal_page_margin"
+ android:paddingRight="@dimen/horizontal_page_margin"
+ android:paddingTop="@dimen/vertical_page_margin"
+ android:paddingBottom="@dimen/vertical_page_margin"
+ android:text="@string/intro_message" />
+ </ScrollView>
+
+ <fragment
+ android:name="com.example.android.common.logger.LogFragment"
+ android:id="@+id/log_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ </ViewAnimator>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@android:color/darker_gray" />
+
+ <FrameLayout
+ android:id="@+id/sample_content_fragment"
+ android:layout_weight="2"
+ android:layout_width="match_parent"
+ android:layout_height="0px" />
+
+</LinearLayout>
+
diff --git a/samples/browseable/SlidingTabsBasic/res/layout/fragment_sample.xml b/samples/browseable/SlidingTabsBasic/res/layout/fragment_sample.xml
new file mode 100644
index 000000000..6ac3690ae
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/res/layout/fragment_sample.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <com.example.android.common.view.SlidingTabLayout
+ android:id="@+id/sliding_tabs"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <android.support.v4.view.ViewPager
+ android:id="@+id/viewpager"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1"
+ android:background="@android:color/white"/>
+
+</LinearLayout> \ No newline at end of file
diff --git a/samples/browseable/SlidingTabsBasic/res/layout/pager_item.xml b/samples/browseable/SlidingTabsBasic/res/layout/pager_item.xml
new file mode 100644
index 000000000..ce4413f06
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/res/layout/pager_item.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:gravity="center">
+
+ <TextView
+ android:id="@+id/item_subtitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:text="Page:"/>
+
+ <TextView
+ android:id="@+id/item_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="80sp" />
+
+</LinearLayout> \ No newline at end of file
diff --git a/samples/browseable/SlidingTabsBasic/res/menu/main.xml b/samples/browseable/SlidingTabsBasic/res/menu/main.xml
new file mode 100644
index 000000000..b49c2c526
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/res/menu/main.xml
@@ -0,0 +1,21 @@
+<!--
+ Copyright 2013 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.
+ -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/menu_toggle_log"
+ android:showAsAction="always"
+ android:title="@string/sample_show_log" />
+</menu>
diff --git a/samples/browseable/SlidingTabsBasic/res/values-sw600dp/template-dimens.xml b/samples/browseable/SlidingTabsBasic/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 000000000..22074a2bd
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/SlidingTabsBasic/res/values-sw600dp/template-styles.xml b/samples/browseable/SlidingTabsBasic/res/values-sw600dp/template-styles.xml
new file mode 100644
index 000000000..03d197418
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceLarge</item>
+ <item name="android:lineSpacingMultiplier">1.2</item>
+ <item name="android:shadowDy">-6.5</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/SlidingTabsBasic/res/values/base-strings.xml b/samples/browseable/SlidingTabsBasic/res/values/base-strings.xml
new file mode 100644
index 000000000..c7f26bf55
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/res/values/base-strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+ <string name="app_name">SlidingTabsBasic</string>
+ <string name="intro_message">
+ <![CDATA[
+
+
+ A basic sample which shows how to use SlidingTabLayout to display a custom
+ ViewPager title strip which gives continuous feedback to the user when scrolling.
+
+
+ ]]>
+ </string>
+</resources>
diff --git a/samples/browseable/SlidingTabsBasic/res/values/strings.xml b/samples/browseable/SlidingTabsBasic/res/values/strings.xml
new file mode 100755
index 000000000..7b9d9ec4f
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/res/values/strings.xml
@@ -0,0 +1,19 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="sample_show_log">Show Log</string>
+ <string name="sample_hide_log">Hide Log</string>
+</resources>
diff --git a/samples/browseable/SlidingTabsBasic/res/values/template-dimens.xml b/samples/browseable/SlidingTabsBasic/res/values/template-dimens.xml
new file mode 100644
index 000000000..39e710b5c
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/SlidingTabsBasic/res/values/template-styles.xml b/samples/browseable/SlidingTabsBasic/res/values/template-styles.xml
new file mode 100644
index 000000000..404623e3d
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/SlidingTabsBasic/src/com.example.android.common/activities/SampleActivityBase.java b/samples/browseable/SlidingTabsBasic/src/com.example.android.common/activities/SampleActivityBase.java
new file mode 100644
index 000000000..3228927b7
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/src/com.example.android.common/activities/SampleActivityBase.java
@@ -0,0 +1,52 @@
+/*
+* Copyright 2013 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.example.android.common.activities;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogWrapper;
+
+/**
+ * Base launcher activity, to handle most of the common plumbing for samples.
+ */
+public class SampleActivityBase extends FragmentActivity {
+
+ public static final String TAG = "SampleActivityBase";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ initializeLogging();
+ }
+
+ /** Set up targets to receive log data */
+ public void initializeLogging() {
+ // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+ // Wraps Android's native log framework
+ LogWrapper logWrapper = new LogWrapper();
+ Log.setLogNode(logWrapper);
+
+ Log.i(TAG, "Ready");
+ }
+}
diff --git a/samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/Log.java b/samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/Log.java
new file mode 100644
index 000000000..17503c568
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 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.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+ // Grabbing the native values from Android's native logging facilities,
+ // to make for easy migration and interop.
+ public static final int NONE = -1;
+ public static final int VERBOSE = android.util.Log.VERBOSE;
+ public static final int DEBUG = android.util.Log.DEBUG;
+ public static final int INFO = android.util.Log.INFO;
+ public static final int WARN = android.util.Log.WARN;
+ public static final int ERROR = android.util.Log.ERROR;
+ public static final int ASSERT = android.util.Log.ASSERT;
+
+ // Stores the beginning of the LogNode topology.
+ private static LogNode mLogNode;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public static LogNode getLogNode() {
+ return mLogNode;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to.
+ */
+ public static void setLogNode(LogNode node) {
+ mLogNode = node;
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void println(int priority, String tag, String msg, Throwable tr) {
+ if (mLogNode != null) {
+ mLogNode.println(priority, tag, msg, tr);
+ }
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ */
+ public static void println(int priority, String tag, String msg) {
+ println(priority, tag, msg, null);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void v(String tag, String msg, Throwable tr) {
+ println(VERBOSE, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void v(String tag, String msg) {
+ v(tag, msg, null);
+ }
+
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void d(String tag, String msg, Throwable tr) {
+ println(DEBUG, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void d(String tag, String msg) {
+ d(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void i(String tag, String msg, Throwable tr) {
+ println(INFO, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void i(String tag, String msg) {
+ i(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, String msg, Throwable tr) {
+ println(WARN, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void w(String tag, String msg) {
+ w(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, Throwable tr) {
+ w(tag, null, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void e(String tag, String msg, Throwable tr) {
+ println(ERROR, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void e(String tag, String msg) {
+ e(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, String msg, Throwable tr) {
+ println(ASSERT, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void wtf(String tag, String msg) {
+ wtf(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, Throwable tr) {
+ wtf(tag, null, tr);
+ }
+}
diff --git a/samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/LogFragment.java
new file mode 100644
index 000000000..b302acd4b
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 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.
+*/
+/*
+ * Copyright 2013 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.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+ private LogView mLogView;
+ private ScrollView mScrollView;
+
+ public LogFragment() {}
+
+ public View inflateViews() {
+ mScrollView = new ScrollView(getActivity());
+ ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT);
+ mScrollView.setLayoutParams(scrollParams);
+
+ mLogView = new LogView(getActivity());
+ ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+ logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+ mLogView.setLayoutParams(logParams);
+ mLogView.setClickable(true);
+ mLogView.setFocusable(true);
+ mLogView.setTypeface(Typeface.MONOSPACE);
+
+ // Want to set padding as 16 dips, setPadding takes pixels. Hooray math!
+ int paddingDips = 16;
+ double scale = getResources().getDisplayMetrics().density;
+ int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+ mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+ mLogView.setCompoundDrawablePadding(paddingPixels);
+
+ mLogView.setGravity(Gravity.BOTTOM);
+ mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+ mScrollView.addView(mLogView);
+ return mScrollView;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+
+ View result = inflateViews();
+
+ mLogView.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+ }
+ });
+ return result;
+ }
+
+ public LogView getLogView() {
+ return mLogView;
+ }
+} \ No newline at end of file
diff --git a/samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/LogNode.java b/samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/LogNode.java
new file mode 100644
index 000000000..bc37cabc0
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * 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.example.android.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+ /**
+ * Instructs first LogNode in the list to print the log data provided.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/LogView.java b/samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/LogView.java
new file mode 100644
index 000000000..c01542b91
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 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.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+ public LogView(Context context) {
+ super(context);
+ }
+
+ public LogView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public LogView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ /**
+ * Formats the log data and prints it out to the LogView.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+
+
+ String priorityStr = null;
+
+ // For the purposes of this View, we want to print the priority as readable text.
+ switch(priority) {
+ case android.util.Log.VERBOSE:
+ priorityStr = "VERBOSE";
+ break;
+ case android.util.Log.DEBUG:
+ priorityStr = "DEBUG";
+ break;
+ case android.util.Log.INFO:
+ priorityStr = "INFO";
+ break;
+ case android.util.Log.WARN:
+ priorityStr = "WARN";
+ break;
+ case android.util.Log.ERROR:
+ priorityStr = "ERROR";
+ break;
+ case android.util.Log.ASSERT:
+ priorityStr = "ASSERT";
+ break;
+ default:
+ break;
+ }
+
+ // Handily, the Log class has a facility for converting a stack trace into a usable string.
+ String exceptionStr = null;
+ if (tr != null) {
+ exceptionStr = android.util.Log.getStackTraceString(tr);
+ }
+
+ // Take the priority, tag, message, and exception, and concatenate as necessary
+ // into one usable line of text.
+ final StringBuilder outputBuilder = new StringBuilder();
+
+ String delimiter = "\t";
+ appendIfNotNull(outputBuilder, priorityStr, delimiter);
+ appendIfNotNull(outputBuilder, tag, delimiter);
+ appendIfNotNull(outputBuilder, msg, delimiter);
+ appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+ // In case this was originally called from an AsyncTask or some other off-UI thread,
+ // make sure the update occurs within the UI thread.
+ ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+ @Override
+ public void run() {
+ // Display the text we just generated within the LogView.
+ appendToLog(outputBuilder.toString());
+ }
+ })));
+
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+ * the logger takes so many arguments that might be null, this method helps cut out some of the
+ * agonizing tedium of writing the same 3 lines over and over.
+ * @param source StringBuilder containing the text to append to.
+ * @param addStr The String to append
+ * @param delimiter The String to separate the source and appended strings. A tab or comma,
+ * for instance.
+ * @return The fully concatenated String as a StringBuilder
+ */
+ private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+ if (addStr != null) {
+ if (addStr.length() == 0) {
+ delimiter = "";
+ }
+
+ return source.append(addStr).append(delimiter);
+ }
+ return source;
+ }
+
+ // The next LogNode in the chain.
+ LogNode mNext;
+
+ /** Outputs the string as a new line of log data in the LogView. */
+ public void appendToLog(String s) {
+ append("\n" + s);
+ }
+
+
+}
diff --git a/samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/LogWrapper.java
new file mode 100644
index 000000000..16a9e7ba2
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * 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.example.android.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface. This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+ // For piping: The next node to receive Log data after this one has done its work.
+ private LogNode mNext;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /**
+ * Prints data out to the console using Android's native log mechanism.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ // There actually are log methods that don't take a msg parameter. For now,
+ // if that's the case, just convert null to the empty string and move on.
+ String useMsg = msg;
+ if (useMsg == null) {
+ useMsg = "";
+ }
+
+ // If an exeption was provided, convert that exception to a usable string and attach
+ // it to the end of the msg method.
+ if (tr != null) {
+ msg += "\n" + Log.getStackTraceString(tr);
+ }
+
+ // This is functionally identical to Log.x(tag, useMsg);
+ // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+ Log.println(priority, tag, useMsg);
+
+ // If this isn't the last node in the chain, move things along.
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+}
diff --git a/samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/MessageOnlyLogFilter.java
new file mode 100644
index 000000000..19967dcd4
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 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.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+ LogNode mNext;
+
+ /**
+ * Takes the "next" LogNode as a parameter, to simplify chaining.
+ *
+ * @param next The next LogNode in the pipeline.
+ */
+ public MessageOnlyLogFilter(LogNode next) {
+ mNext = next;
+ }
+
+ public MessageOnlyLogFilter() {
+ }
+
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ if (mNext != null) {
+ getNext().println(Log.NONE, null, msg, null);
+ }
+ }
+
+ /**
+ * Returns the next LogNode in the chain.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+}
diff --git a/samples/browseable/SlidingTabsBasic/src/com.example.android.common/view/SlidingTabLayout.java b/samples/browseable/SlidingTabsBasic/src/com.example.android.common/view/SlidingTabLayout.java
new file mode 100644
index 000000000..20049e335
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/src/com.example.android.common/view/SlidingTabLayout.java
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2013 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.example.android.common.view;
+
+import android.content.Context;
+import android.graphics.Typeface;
+import android.os.Build;
+import android.support.v4.view.PagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.HorizontalScrollView;
+import android.widget.TextView;
+
+/**
+ * To be used with ViewPager to provide a tab indicator component which give constant feedback as to
+ * the user's scroll progress.
+ * <p>
+ * To use the component, simply add it to your view hierarchy. Then in your
+ * {@link android.app.Activity} or {@link android.support.v4.app.Fragment} call
+ * {@link #setViewPager(ViewPager)} providing it the ViewPager this layout is being used for.
+ * <p>
+ * The colors can be customized in two ways. The first and simplest is to provide an array of colors
+ * via {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)}. The
+ * alternative is via the {@link TabColorizer} interface which provides you complete control over
+ * which color is used for any individual position.
+ * <p>
+ * The views used as tabs can be customized by calling {@link #setCustomTabView(int, int)},
+ * providing the layout ID of your custom layout.
+ */
+public class SlidingTabLayout extends HorizontalScrollView {
+
+ /**
+ * Allows complete control over the colors drawn in the tab layout. Set with
+ * {@link #setCustomTabColorizer(TabColorizer)}.
+ */
+ public interface TabColorizer {
+
+ /**
+ * @return return the color of the indicator used when {@code position} is selected.
+ */
+ int getIndicatorColor(int position);
+
+ /**
+ * @return return the color of the divider drawn to the right of {@code position}.
+ */
+ int getDividerColor(int position);
+
+ }
+
+ private static final int TITLE_OFFSET_DIPS = 24;
+ private static final int TAB_VIEW_PADDING_DIPS = 16;
+ private static final int TAB_VIEW_TEXT_SIZE_SP = 12;
+
+ private int mTitleOffset;
+
+ private int mTabViewLayoutId;
+ private int mTabViewTextViewId;
+
+ private ViewPager mViewPager;
+ private ViewPager.OnPageChangeListener mViewPagerPageChangeListener;
+
+ private final SlidingTabStrip mTabStrip;
+
+ public SlidingTabLayout(Context context) {
+ this(context, null);
+ }
+
+ public SlidingTabLayout(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public SlidingTabLayout(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ // Disable the Scroll Bar
+ setHorizontalScrollBarEnabled(false);
+ // Make sure that the Tab Strips fills this View
+ setFillViewport(true);
+
+ mTitleOffset = (int) (TITLE_OFFSET_DIPS * getResources().getDisplayMetrics().density);
+
+ mTabStrip = new SlidingTabStrip(context);
+ addView(mTabStrip, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+ }
+
+ /**
+ * Set the custom {@link TabColorizer} to be used.
+ *
+ * If you only require simple custmisation then you can use
+ * {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)} to achieve
+ * similar effects.
+ */
+ public void setCustomTabColorizer(TabColorizer tabColorizer) {
+ mTabStrip.setCustomTabColorizer(tabColorizer);
+ }
+
+ /**
+ * Sets the colors to be used for indicating the selected tab. These colors are treated as a
+ * circular array. Providing one color will mean that all tabs are indicated with the same color.
+ */
+ public void setSelectedIndicatorColors(int... colors) {
+ mTabStrip.setSelectedIndicatorColors(colors);
+ }
+
+ /**
+ * Sets the colors to be used for tab dividers. These colors are treated as a circular array.
+ * Providing one color will mean that all tabs are indicated with the same color.
+ */
+ public void setDividerColors(int... colors) {
+ mTabStrip.setDividerColors(colors);
+ }
+
+ /**
+ * Set the {@link ViewPager.OnPageChangeListener}. When using {@link SlidingTabLayout} you are
+ * required to set any {@link ViewPager.OnPageChangeListener} through this method. This is so
+ * that the layout can update it's scroll position correctly.
+ *
+ * @see ViewPager#setOnPageChangeListener(ViewPager.OnPageChangeListener)
+ */
+ public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
+ mViewPagerPageChangeListener = listener;
+ }
+
+ /**
+ * Set the custom layout to be inflated for the tab views.
+ *
+ * @param layoutResId Layout id to be inflated
+ * @param textViewId id of the {@link TextView} in the inflated view
+ */
+ public void setCustomTabView(int layoutResId, int textViewId) {
+ mTabViewLayoutId = layoutResId;
+ mTabViewTextViewId = textViewId;
+ }
+
+ /**
+ * Sets the associated view pager. Note that the assumption here is that the pager content
+ * (number of tabs and tab titles) does not change after this call has been made.
+ */
+ public void setViewPager(ViewPager viewPager) {
+ mTabStrip.removeAllViews();
+
+ mViewPager = viewPager;
+ if (viewPager != null) {
+ viewPager.setOnPageChangeListener(new InternalViewPagerListener());
+ populateTabStrip();
+ }
+ }
+
+ /**
+ * Create a default view to be used for tabs. This is called if a custom tab view is not set via
+ * {@link #setCustomTabView(int, int)}.
+ */
+ protected TextView createDefaultTabView(Context context) {
+ TextView textView = new TextView(context);
+ textView.setGravity(Gravity.CENTER);
+ textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, TAB_VIEW_TEXT_SIZE_SP);
+ textView.setTypeface(Typeface.DEFAULT_BOLD);
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ // If we're running on Honeycomb or newer, then we can use the Theme's
+ // selectableItemBackground to ensure that the View has a pressed state
+ TypedValue outValue = new TypedValue();
+ getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground,
+ outValue, true);
+ textView.setBackgroundResource(outValue.resourceId);
+ }
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ // If we're running on ICS or newer, enable all-caps to match the Action Bar tab style
+ textView.setAllCaps(true);
+ }
+
+ int padding = (int) (TAB_VIEW_PADDING_DIPS * getResources().getDisplayMetrics().density);
+ textView.setPadding(padding, padding, padding, padding);
+
+ return textView;
+ }
+
+ private void populateTabStrip() {
+ final PagerAdapter adapter = mViewPager.getAdapter();
+ final View.OnClickListener tabClickListener = new TabClickListener();
+
+ for (int i = 0; i < adapter.getCount(); i++) {
+ View tabView = null;
+ TextView tabTitleView = null;
+
+ if (mTabViewLayoutId != 0) {
+ // If there is a custom tab view layout id set, try and inflate it
+ tabView = LayoutInflater.from(getContext()).inflate(mTabViewLayoutId, mTabStrip,
+ false);
+ tabTitleView = (TextView) tabView.findViewById(mTabViewTextViewId);
+ }
+
+ if (tabView == null) {
+ tabView = createDefaultTabView(getContext());
+ }
+
+ if (tabTitleView == null && TextView.class.isInstance(tabView)) {
+ tabTitleView = (TextView) tabView;
+ }
+
+ tabTitleView.setText(adapter.getPageTitle(i));
+ tabView.setOnClickListener(tabClickListener);
+
+ mTabStrip.addView(tabView);
+ }
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ if (mViewPager != null) {
+ scrollToTab(mViewPager.getCurrentItem(), 0);
+ }
+ }
+
+ private void scrollToTab(int tabIndex, int positionOffset) {
+ final int tabStripChildCount = mTabStrip.getChildCount();
+ if (tabStripChildCount == 0 || tabIndex < 0 || tabIndex >= tabStripChildCount) {
+ return;
+ }
+
+ View selectedChild = mTabStrip.getChildAt(tabIndex);
+ if (selectedChild != null) {
+ int targetScrollX = selectedChild.getLeft() + positionOffset;
+
+ if (tabIndex > 0 || positionOffset > 0) {
+ // If we're not at the first child and are mid-scroll, make sure we obey the offset
+ targetScrollX -= mTitleOffset;
+ }
+
+ scrollTo(targetScrollX, 0);
+ }
+ }
+
+ private class InternalViewPagerListener implements ViewPager.OnPageChangeListener {
+ private int mScrollState;
+
+ @Override
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+ int tabStripChildCount = mTabStrip.getChildCount();
+ if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) {
+ return;
+ }
+
+ mTabStrip.onViewPagerPageChanged(position, positionOffset);
+
+ View selectedTitle = mTabStrip.getChildAt(position);
+ int extraOffset = (selectedTitle != null)
+ ? (int) (positionOffset * selectedTitle.getWidth())
+ : 0;
+ scrollToTab(position, extraOffset);
+
+ if (mViewPagerPageChangeListener != null) {
+ mViewPagerPageChangeListener.onPageScrolled(position, positionOffset,
+ positionOffsetPixels);
+ }
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int state) {
+ mScrollState = state;
+
+ if (mViewPagerPageChangeListener != null) {
+ mViewPagerPageChangeListener.onPageScrollStateChanged(state);
+ }
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ if (mScrollState == ViewPager.SCROLL_STATE_IDLE) {
+ mTabStrip.onViewPagerPageChanged(position, 0f);
+ scrollToTab(position, 0);
+ }
+
+ if (mViewPagerPageChangeListener != null) {
+ mViewPagerPageChangeListener.onPageSelected(position);
+ }
+ }
+
+ }
+
+ private class TabClickListener implements View.OnClickListener {
+ @Override
+ public void onClick(View v) {
+ for (int i = 0; i < mTabStrip.getChildCount(); i++) {
+ if (v == mTabStrip.getChildAt(i)) {
+ mViewPager.setCurrentItem(i);
+ return;
+ }
+ }
+ }
+ }
+
+}
diff --git a/samples/browseable/SlidingTabsBasic/src/com.example.android.common/view/SlidingTabStrip.java b/samples/browseable/SlidingTabsBasic/src/com.example.android.common/view/SlidingTabStrip.java
new file mode 100644
index 000000000..d5bbbae59
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/src/com.example.android.common/view/SlidingTabStrip.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2013 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.example.android.common.view;
+
+import android.R;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.View;
+import android.widget.LinearLayout;
+
+class SlidingTabStrip extends LinearLayout {
+
+ private static final int DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS = 2;
+ private static final byte DEFAULT_BOTTOM_BORDER_COLOR_ALPHA = 0x26;
+ private static final int SELECTED_INDICATOR_THICKNESS_DIPS = 8;
+ private static final int DEFAULT_SELECTED_INDICATOR_COLOR = 0xFF33B5E5;
+
+ private static final int DEFAULT_DIVIDER_THICKNESS_DIPS = 1;
+ private static final byte DEFAULT_DIVIDER_COLOR_ALPHA = 0x20;
+ private static final float DEFAULT_DIVIDER_HEIGHT = 0.5f;
+
+ private final int mBottomBorderThickness;
+ private final Paint mBottomBorderPaint;
+
+ private final int mSelectedIndicatorThickness;
+ private final Paint mSelectedIndicatorPaint;
+
+ private final int mDefaultBottomBorderColor;
+
+ private final Paint mDividerPaint;
+ private final float mDividerHeight;
+
+ private int mSelectedPosition;
+ private float mSelectionOffset;
+
+ private SlidingTabLayout.TabColorizer mCustomTabColorizer;
+ private final SimpleTabColorizer mDefaultTabColorizer;
+
+ SlidingTabStrip(Context context) {
+ this(context, null);
+ }
+
+ SlidingTabStrip(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setWillNotDraw(false);
+
+ final float density = getResources().getDisplayMetrics().density;
+
+ TypedValue outValue = new TypedValue();
+ context.getTheme().resolveAttribute(R.attr.colorForeground, outValue, true);
+ final int themeForegroundColor = outValue.data;
+
+ mDefaultBottomBorderColor = setColorAlpha(themeForegroundColor,
+ DEFAULT_BOTTOM_BORDER_COLOR_ALPHA);
+
+ mDefaultTabColorizer = new SimpleTabColorizer();
+ mDefaultTabColorizer.setIndicatorColors(DEFAULT_SELECTED_INDICATOR_COLOR);
+ mDefaultTabColorizer.setDividerColors(setColorAlpha(themeForegroundColor,
+ DEFAULT_DIVIDER_COLOR_ALPHA));
+
+ mBottomBorderThickness = (int) (DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS * density);
+ mBottomBorderPaint = new Paint();
+ mBottomBorderPaint.setColor(mDefaultBottomBorderColor);
+
+ mSelectedIndicatorThickness = (int) (SELECTED_INDICATOR_THICKNESS_DIPS * density);
+ mSelectedIndicatorPaint = new Paint();
+
+ mDividerHeight = DEFAULT_DIVIDER_HEIGHT;
+ mDividerPaint = new Paint();
+ mDividerPaint.setStrokeWidth((int) (DEFAULT_DIVIDER_THICKNESS_DIPS * density));
+ }
+
+ void setCustomTabColorizer(SlidingTabLayout.TabColorizer customTabColorizer) {
+ mCustomTabColorizer = customTabColorizer;
+ invalidate();
+ }
+
+ void setSelectedIndicatorColors(int... colors) {
+ // Make sure that the custom colorizer is removed
+ mCustomTabColorizer = null;
+ mDefaultTabColorizer.setIndicatorColors(colors);
+ invalidate();
+ }
+
+ void setDividerColors(int... colors) {
+ // Make sure that the custom colorizer is removed
+ mCustomTabColorizer = null;
+ mDefaultTabColorizer.setDividerColors(colors);
+ invalidate();
+ }
+
+ void onViewPagerPageChanged(int position, float positionOffset) {
+ mSelectedPosition = position;
+ mSelectionOffset = positionOffset;
+ invalidate();
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ final int height = getHeight();
+ final int childCount = getChildCount();
+ final int dividerHeightPx = (int) (Math.min(Math.max(0f, mDividerHeight), 1f) * height);
+ final SlidingTabLayout.TabColorizer tabColorizer = mCustomTabColorizer != null
+ ? mCustomTabColorizer
+ : mDefaultTabColorizer;
+
+ // Thick colored underline below the current selection
+ if (childCount > 0) {
+ View selectedTitle = getChildAt(mSelectedPosition);
+ int left = selectedTitle.getLeft();
+ int right = selectedTitle.getRight();
+ int color = tabColorizer.getIndicatorColor(mSelectedPosition);
+
+ if (mSelectionOffset > 0f && mSelectedPosition < (getChildCount() - 1)) {
+ int nextColor = tabColorizer.getIndicatorColor(mSelectedPosition + 1);
+ if (color != nextColor) {
+ color = blendColors(nextColor, color, mSelectionOffset);
+ }
+
+ // Draw the selection partway between the tabs
+ View nextTitle = getChildAt(mSelectedPosition + 1);
+ left = (int) (mSelectionOffset * nextTitle.getLeft() +
+ (1.0f - mSelectionOffset) * left);
+ right = (int) (mSelectionOffset * nextTitle.getRight() +
+ (1.0f - mSelectionOffset) * right);
+ }
+
+ mSelectedIndicatorPaint.setColor(color);
+
+ canvas.drawRect(left, height - mSelectedIndicatorThickness, right,
+ height, mSelectedIndicatorPaint);
+ }
+
+ // Thin underline along the entire bottom edge
+ canvas.drawRect(0, height - mBottomBorderThickness, getWidth(), height, mBottomBorderPaint);
+
+ // Vertical separators between the titles
+ int separatorTop = (height - dividerHeightPx) / 2;
+ for (int i = 0; i < childCount - 1; i++) {
+ View child = getChildAt(i);
+ mDividerPaint.setColor(tabColorizer.getDividerColor(i));
+ canvas.drawLine(child.getRight(), separatorTop, child.getRight(),
+ separatorTop + dividerHeightPx, mDividerPaint);
+ }
+ }
+
+ /**
+ * Set the alpha value of the {@code color} to be the given {@code alpha} value.
+ */
+ private static int setColorAlpha(int color, byte alpha) {
+ return Color.argb(alpha, Color.red(color), Color.green(color), Color.blue(color));
+ }
+
+ /**
+ * Blend {@code color1} and {@code color2} using the given ratio.
+ *
+ * @param ratio of which to blend. 1.0 will return {@code color1}, 0.5 will give an even blend,
+ * 0.0 will return {@code color2}.
+ */
+ private static int blendColors(int color1, int color2, float ratio) {
+ final float inverseRation = 1f - ratio;
+ float r = (Color.red(color1) * ratio) + (Color.red(color2) * inverseRation);
+ float g = (Color.green(color1) * ratio) + (Color.green(color2) * inverseRation);
+ float b = (Color.blue(color1) * ratio) + (Color.blue(color2) * inverseRation);
+ return Color.rgb((int) r, (int) g, (int) b);
+ }
+
+ private static class SimpleTabColorizer implements SlidingTabLayout.TabColorizer {
+ private int[] mIndicatorColors;
+ private int[] mDividerColors;
+
+ @Override
+ public final int getIndicatorColor(int position) {
+ return mIndicatorColors[position % mIndicatorColors.length];
+ }
+
+ @Override
+ public final int getDividerColor(int position) {
+ return mDividerColors[position % mDividerColors.length];
+ }
+
+ void setIndicatorColors(int... colors) {
+ mIndicatorColors = colors;
+ }
+
+ void setDividerColors(int... colors) {
+ mDividerColors = colors;
+ }
+ }
+} \ No newline at end of file
diff --git a/samples/browseable/SlidingTabsBasic/src/com.example.android.slidingtabsbasic/MainActivity.java b/samples/browseable/SlidingTabsBasic/src/com.example.android.slidingtabsbasic/MainActivity.java
new file mode 100644
index 000000000..ac405d19b
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/src/com.example.android.slidingtabsbasic/MainActivity.java
@@ -0,0 +1,110 @@
+/*
+* Copyright 2013 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.example.android.slidingtabsbasic;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.ViewAnimator;
+
+import com.example.android.common.activities.SampleActivityBase;
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogFragment;
+import com.example.android.common.logger.LogWrapper;
+import com.example.android.common.logger.MessageOnlyLogFilter;
+
+/**
+ * A simple launcher activity containing a summary sample description, sample log and a custom
+ * {@link android.support.v4.app.Fragment} which can display a view.
+ * <p>
+ * For devices with displays with a width of 720dp or greater, the sample log is always visible,
+ * on other devices it's visibility is controlled by an item on the Action Bar.
+ */
+public class MainActivity extends SampleActivityBase {
+
+ public static final String TAG = "MainActivity";
+
+ // Whether the Log Fragment is currently shown
+ private boolean mLogShown;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+ SlidingTabsBasicFragment fragment = new SlidingTabsBasicFragment();
+ transaction.replace(R.id.sample_content_fragment, fragment);
+ transaction.commit();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.main, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ MenuItem logToggle = menu.findItem(R.id.menu_toggle_log);
+ logToggle.setVisible(findViewById(R.id.sample_output) instanceof ViewAnimator);
+ logToggle.setTitle(mLogShown ? R.string.sample_hide_log : R.string.sample_show_log);
+
+ return super.onPrepareOptionsMenu(menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch(item.getItemId()) {
+ case R.id.menu_toggle_log:
+ mLogShown = !mLogShown;
+ ViewAnimator output = (ViewAnimator) findViewById(R.id.sample_output);
+ if (mLogShown) {
+ output.setDisplayedChild(1);
+ } else {
+ output.setDisplayedChild(0);
+ }
+ supportInvalidateOptionsMenu();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ /** Create a chain of targets that will receive log data */
+ @Override
+ public void initializeLogging() {
+ // Wraps Android's native log framework.
+ LogWrapper logWrapper = new LogWrapper();
+ // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+ Log.setLogNode(logWrapper);
+
+ // Filter strips out everything except the message text.
+ MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
+ logWrapper.setNext(msgFilter);
+
+ // On screen logging via a fragment with a TextView.
+ LogFragment logFragment = (LogFragment) getSupportFragmentManager()
+ .findFragmentById(R.id.log_fragment);
+ msgFilter.setNext(logFragment.getLogView());
+
+ Log.i(TAG, "Ready");
+ }
+}
diff --git a/samples/browseable/SlidingTabsBasic/src/com.example.android.slidingtabsbasic/SlidingTabsBasicFragment.java b/samples/browseable/SlidingTabsBasic/src/com.example.android.slidingtabsbasic/SlidingTabsBasicFragment.java
new file mode 100644
index 000000000..80f7b10fe
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/src/com.example.android.slidingtabsbasic/SlidingTabsBasicFragment.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2013 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.example.android.slidingtabsbasic;
+
+import com.example.android.common.logger.Log;
+import com.example.android.common.view.SlidingTabLayout;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.view.PagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+/**
+ * A basic sample which shows how to use {@link com.example.android.common.view.SlidingTabLayout}
+ * to display a custom {@link ViewPager} title strip which gives continuous feedback to the user
+ * when scrolling.
+ */
+public class SlidingTabsBasicFragment extends Fragment {
+
+ static final String LOG_TAG = "SlidingTabsBasicFragment";
+
+ /**
+ * A custom {@link ViewPager} title strip which looks much like Tabs present in Android v4.0 and
+ * above, but is designed to give continuous feedback to the user when scrolling.
+ */
+ private SlidingTabLayout mSlidingTabLayout;
+
+ /**
+ * A {@link ViewPager} which will be used in conjunction with the {@link SlidingTabLayout} above.
+ */
+ private ViewPager mViewPager;
+
+ /**
+ * Inflates the {@link View} which will be displayed by this {@link Fragment}, from the app's
+ * resources.
+ */
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fragment_sample, container, false);
+ }
+
+ // BEGIN_INCLUDE (fragment_onviewcreated)
+ /**
+ * This is called after the {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)} has finished.
+ * Here we can pick out the {@link View}s we need to configure from the content view.
+ *
+ * We set the {@link ViewPager}'s adapter to be an instance of {@link SamplePagerAdapter}. The
+ * {@link SlidingTabLayout} is then given the {@link ViewPager} so that it can populate itself.
+ *
+ * @param view View created in {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}
+ */
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ // BEGIN_INCLUDE (setup_viewpager)
+ // Get the ViewPager and set it's PagerAdapter so that it can display items
+ mViewPager = (ViewPager) view.findViewById(R.id.viewpager);
+ mViewPager.setAdapter(new SamplePagerAdapter());
+ // END_INCLUDE (setup_viewpager)
+
+ // BEGIN_INCLUDE (setup_slidingtablayout)
+ // Give the SlidingTabLayout the ViewPager, this must be done AFTER the ViewPager has had
+ // it's PagerAdapter set.
+ mSlidingTabLayout = (SlidingTabLayout) view.findViewById(R.id.sliding_tabs);
+ mSlidingTabLayout.setViewPager(mViewPager);
+ // END_INCLUDE (setup_slidingtablayout)
+ }
+ // END_INCLUDE (fragment_onviewcreated)
+
+ /**
+ * The {@link android.support.v4.view.PagerAdapter} used to display pages in this sample.
+ * The individual pages are simple and just display two lines of text. The important section of
+ * this class is the {@link #getPageTitle(int)} method which controls what is displayed in the
+ * {@link SlidingTabLayout}.
+ */
+ class SamplePagerAdapter extends PagerAdapter {
+
+ /**
+ * @return the number of pages to display
+ */
+ @Override
+ public int getCount() {
+ return 10;
+ }
+
+ /**
+ * @return true if the value returned from {@link #instantiateItem(ViewGroup, int)} is the
+ * same object as the {@link View} added to the {@link ViewPager}.
+ */
+ @Override
+ public boolean isViewFromObject(View view, Object o) {
+ return o == view;
+ }
+
+ // BEGIN_INCLUDE (pageradapter_getpagetitle)
+ /**
+ * Return the title of the item at {@code position}. This is important as what this method
+ * returns is what is displayed in the {@link SlidingTabLayout}.
+ * <p>
+ * Here we construct one using the position value, but for real application the title should
+ * refer to the item's contents.
+ */
+ @Override
+ public CharSequence getPageTitle(int position) {
+ return "Item " + (position + 1);
+ }
+ // END_INCLUDE (pageradapter_getpagetitle)
+
+ /**
+ * Instantiate the {@link View} which should be displayed at {@code position}. Here we
+ * inflate a layout from the apps resources and then change the text view to signify the position.
+ */
+ @Override
+ public Object instantiateItem(ViewGroup container, int position) {
+ // Inflate a new layout from our resources
+ View view = getActivity().getLayoutInflater().inflate(R.layout.pager_item,
+ container, false);
+ // Add the newly created View to the ViewPager
+ container.addView(view);
+
+ // Retrieve a TextView from the inflated View, and update it's text
+ TextView title = (TextView) view.findViewById(R.id.item_title);
+ title.setText(String.valueOf(position + 1));
+
+ Log.i(LOG_TAG, "instantiateItem() [position: " + position + "]");
+
+ // Return the View
+ return view;
+ }
+
+ /**
+ * Destroy the item from the {@link ViewPager}. In our case this is simply removing the
+ * {@link View}.
+ */
+ @Override
+ public void destroyItem(ViewGroup container, int position, Object object) {
+ container.removeView((View) object);
+ Log.i(LOG_TAG, "destroyItem() [position: " + position + "]");
+ }
+
+ }
+}
diff --git a/samples/browseable/SlidingTabsColors/AndroidManifest.xml b/samples/browseable/SlidingTabsColors/AndroidManifest.xml
new file mode 100644
index 000000000..be4a43ad2
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/AndroidManifest.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 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.
+-->
+
+
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.slidingtabscolors"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="19" />
+
+ <application android:allowBackup="true"
+ android:label="@string/app_name"
+ android:icon="@drawable/ic_launcher"
+ android:theme="@style/AppTheme">
+
+ <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>
+ </application>
+
+
+</manifest>
diff --git a/samples/browseable/SlidingTabsColors/_index.jd b/samples/browseable/SlidingTabsColors/_index.jd
new file mode 100644
index 000000000..ee1b853ec
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/_index.jd
@@ -0,0 +1,13 @@
+
+
+
+page.tags="SlidingTabsColors"
+sample.group=UI
+@jd:body
+
+<p>
+
+ A more advanced sample which shows how to use SlidingTabLayout to display a custom
+ ViewPager title strip, with custom coloring for each tab.
+
+ </p>
diff --git a/samples/browseable/SlidingTabsColors/res/drawable-hdpi/ic_launcher.png b/samples/browseable/SlidingTabsColors/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 000000000..66542eecf
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/SlidingTabsColors/res/drawable-hdpi/tile.9.png b/samples/browseable/SlidingTabsColors/res/drawable-hdpi/tile.9.png
new file mode 100644
index 000000000..135862883
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/SlidingTabsColors/res/drawable-mdpi/ic_launcher.png b/samples/browseable/SlidingTabsColors/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 000000000..56e472620
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/SlidingTabsColors/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/SlidingTabsColors/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..ba41664e2
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/SlidingTabsColors/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/SlidingTabsColors/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..c9a51f608
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/SlidingTabsColors/res/layout-w720dp/activity_main.xml b/samples/browseable/SlidingTabsColors/res/layout-w720dp/activity_main.xml
new file mode 100755
index 000000000..c9a52f621
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/res/layout-w720dp/activity_main.xml
@@ -0,0 +1,73 @@
+<!--
+ Copyright 2013 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.
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/sample_main_layout">
+
+ <LinearLayout
+ android:id="@+id/sample_output"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:orientation="vertical">
+
+ <FrameLayout
+ style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/margin_medium"
+ android:paddingRight="@dimen/margin_medium"
+ android:paddingTop="@dimen/margin_large"
+ android:paddingBottom="@dimen/margin_large"
+ android:text="@string/intro_message" />
+ </FrameLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@android:color/darker_gray" />
+
+ <fragment
+ android:name="com.example.android.common.logger.LogFragment"
+ android:id="@+id/log_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1" />
+
+ </LinearLayout>
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:background="@android:color/darker_gray" />
+
+ <FrameLayout
+ android:id="@+id/sample_content_fragment"
+ android:layout_weight="2"
+ android:layout_width="0px"
+ android:layout_height="match_parent" />
+
+</LinearLayout>
+
+
diff --git a/samples/browseable/SlidingTabsColors/res/layout/activity_main.xml b/samples/browseable/SlidingTabsColors/res/layout/activity_main.xml
new file mode 100755
index 000000000..1ae4f981e
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/res/layout/activity_main.xml
@@ -0,0 +1,65 @@
+<!--
+ Copyright 2013 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.
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/sample_main_layout">
+
+ <ViewAnimator
+ android:id="@+id/sample_output"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1">
+
+ <ScrollView
+ style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/horizontal_page_margin"
+ android:paddingRight="@dimen/horizontal_page_margin"
+ android:paddingTop="@dimen/vertical_page_margin"
+ android:paddingBottom="@dimen/vertical_page_margin"
+ android:text="@string/intro_message" />
+ </ScrollView>
+
+ <fragment
+ android:name="com.example.android.common.logger.LogFragment"
+ android:id="@+id/log_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ </ViewAnimator>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@android:color/darker_gray" />
+
+ <FrameLayout
+ android:id="@+id/sample_content_fragment"
+ android:layout_weight="2"
+ android:layout_width="match_parent"
+ android:layout_height="0px" />
+
+</LinearLayout>
+
diff --git a/samples/browseable/SlidingTabsColors/res/layout/fragment_sample.xml b/samples/browseable/SlidingTabsColors/res/layout/fragment_sample.xml
new file mode 100644
index 000000000..605cba7e0
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/res/layout/fragment_sample.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <com.example.android.common.view.SlidingTabLayout
+ android:id="@+id/sliding_tabs"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <android.support.v4.view.ViewPager
+ android:id="@+id/viewpager"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1"
+ android:background="@android:color/white" />
+
+</LinearLayout> \ No newline at end of file
diff --git a/samples/browseable/SlidingTabsColors/res/layout/pager_item.xml b/samples/browseable/SlidingTabsColors/res/layout/pager_item.xml
new file mode 100644
index 000000000..039ceb106
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/res/layout/pager_item.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:gravity="center">
+
+ <TextView
+ android:id="@+id/item_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceLarge" />
+
+ <TextView
+ android:id="@+id/item_indicator_color"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceLarge" />
+
+ <TextView
+ android:id="@+id/item_divider_color"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceLarge" />
+
+</LinearLayout> \ No newline at end of file
diff --git a/samples/browseable/SlidingTabsColors/res/menu/main.xml b/samples/browseable/SlidingTabsColors/res/menu/main.xml
new file mode 100644
index 000000000..b49c2c526
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/res/menu/main.xml
@@ -0,0 +1,21 @@
+<!--
+ Copyright 2013 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.
+ -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/menu_toggle_log"
+ android:showAsAction="always"
+ android:title="@string/sample_show_log" />
+</menu>
diff --git a/samples/browseable/SlidingTabsColors/res/values-sw600dp/template-dimens.xml b/samples/browseable/SlidingTabsColors/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 000000000..22074a2bd
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/SlidingTabsColors/res/values-sw600dp/template-styles.xml b/samples/browseable/SlidingTabsColors/res/values-sw600dp/template-styles.xml
new file mode 100644
index 000000000..03d197418
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceLarge</item>
+ <item name="android:lineSpacingMultiplier">1.2</item>
+ <item name="android:shadowDy">-6.5</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/SlidingTabsColors/res/values/base-strings.xml b/samples/browseable/SlidingTabsColors/res/values/base-strings.xml
new file mode 100644
index 000000000..89cac2d6e
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/res/values/base-strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+ <string name="app_name">SlidingTabsColors</string>
+ <string name="intro_message">
+ <![CDATA[
+
+
+ A more advanced sample which shows how to use SlidingTabLayout to display a custom
+ ViewPager title strip, with custom coloring for each tab.
+
+
+ ]]>
+ </string>
+</resources>
diff --git a/samples/browseable/SlidingTabsColors/res/values/strings.xml b/samples/browseable/SlidingTabsColors/res/values/strings.xml
new file mode 100755
index 000000000..7b9d9ec4f
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/res/values/strings.xml
@@ -0,0 +1,19 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="sample_show_log">Show Log</string>
+ <string name="sample_hide_log">Hide Log</string>
+</resources>
diff --git a/samples/browseable/SlidingTabsColors/res/values/template-dimens.xml b/samples/browseable/SlidingTabsColors/res/values/template-dimens.xml
new file mode 100644
index 000000000..39e710b5c
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/SlidingTabsColors/res/values/template-styles.xml b/samples/browseable/SlidingTabsColors/res/values/template-styles.xml
new file mode 100644
index 000000000..404623e3d
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/SlidingTabsColors/src/com.example.android.common/activities/SampleActivityBase.java b/samples/browseable/SlidingTabsColors/src/com.example.android.common/activities/SampleActivityBase.java
new file mode 100644
index 000000000..3228927b7
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/src/com.example.android.common/activities/SampleActivityBase.java
@@ -0,0 +1,52 @@
+/*
+* Copyright 2013 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.example.android.common.activities;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogWrapper;
+
+/**
+ * Base launcher activity, to handle most of the common plumbing for samples.
+ */
+public class SampleActivityBase extends FragmentActivity {
+
+ public static final String TAG = "SampleActivityBase";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ initializeLogging();
+ }
+
+ /** Set up targets to receive log data */
+ public void initializeLogging() {
+ // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+ // Wraps Android's native log framework
+ LogWrapper logWrapper = new LogWrapper();
+ Log.setLogNode(logWrapper);
+
+ Log.i(TAG, "Ready");
+ }
+}
diff --git a/samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/Log.java b/samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/Log.java
new file mode 100644
index 000000000..17503c568
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 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.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+ // Grabbing the native values from Android's native logging facilities,
+ // to make for easy migration and interop.
+ public static final int NONE = -1;
+ public static final int VERBOSE = android.util.Log.VERBOSE;
+ public static final int DEBUG = android.util.Log.DEBUG;
+ public static final int INFO = android.util.Log.INFO;
+ public static final int WARN = android.util.Log.WARN;
+ public static final int ERROR = android.util.Log.ERROR;
+ public static final int ASSERT = android.util.Log.ASSERT;
+
+ // Stores the beginning of the LogNode topology.
+ private static LogNode mLogNode;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public static LogNode getLogNode() {
+ return mLogNode;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to.
+ */
+ public static void setLogNode(LogNode node) {
+ mLogNode = node;
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void println(int priority, String tag, String msg, Throwable tr) {
+ if (mLogNode != null) {
+ mLogNode.println(priority, tag, msg, tr);
+ }
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ */
+ public static void println(int priority, String tag, String msg) {
+ println(priority, tag, msg, null);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void v(String tag, String msg, Throwable tr) {
+ println(VERBOSE, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void v(String tag, String msg) {
+ v(tag, msg, null);
+ }
+
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void d(String tag, String msg, Throwable tr) {
+ println(DEBUG, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void d(String tag, String msg) {
+ d(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void i(String tag, String msg, Throwable tr) {
+ println(INFO, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void i(String tag, String msg) {
+ i(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, String msg, Throwable tr) {
+ println(WARN, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void w(String tag, String msg) {
+ w(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, Throwable tr) {
+ w(tag, null, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void e(String tag, String msg, Throwable tr) {
+ println(ERROR, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void e(String tag, String msg) {
+ e(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, String msg, Throwable tr) {
+ println(ASSERT, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void wtf(String tag, String msg) {
+ wtf(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, Throwable tr) {
+ wtf(tag, null, tr);
+ }
+}
diff --git a/samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/LogFragment.java
new file mode 100644
index 000000000..b302acd4b
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 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.
+*/
+/*
+ * Copyright 2013 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.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+ private LogView mLogView;
+ private ScrollView mScrollView;
+
+ public LogFragment() {}
+
+ public View inflateViews() {
+ mScrollView = new ScrollView(getActivity());
+ ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT);
+ mScrollView.setLayoutParams(scrollParams);
+
+ mLogView = new LogView(getActivity());
+ ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+ logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+ mLogView.setLayoutParams(logParams);
+ mLogView.setClickable(true);
+ mLogView.setFocusable(true);
+ mLogView.setTypeface(Typeface.MONOSPACE);
+
+ // Want to set padding as 16 dips, setPadding takes pixels. Hooray math!
+ int paddingDips = 16;
+ double scale = getResources().getDisplayMetrics().density;
+ int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+ mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+ mLogView.setCompoundDrawablePadding(paddingPixels);
+
+ mLogView.setGravity(Gravity.BOTTOM);
+ mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+ mScrollView.addView(mLogView);
+ return mScrollView;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+
+ View result = inflateViews();
+
+ mLogView.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+ }
+ });
+ return result;
+ }
+
+ public LogView getLogView() {
+ return mLogView;
+ }
+} \ No newline at end of file
diff --git a/samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/LogNode.java b/samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/LogNode.java
new file mode 100644
index 000000000..bc37cabc0
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * 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.example.android.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+ /**
+ * Instructs first LogNode in the list to print the log data provided.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/LogView.java b/samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/LogView.java
new file mode 100644
index 000000000..c01542b91
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 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.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+ public LogView(Context context) {
+ super(context);
+ }
+
+ public LogView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public LogView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ /**
+ * Formats the log data and prints it out to the LogView.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+
+
+ String priorityStr = null;
+
+ // For the purposes of this View, we want to print the priority as readable text.
+ switch(priority) {
+ case android.util.Log.VERBOSE:
+ priorityStr = "VERBOSE";
+ break;
+ case android.util.Log.DEBUG:
+ priorityStr = "DEBUG";
+ break;
+ case android.util.Log.INFO:
+ priorityStr = "INFO";
+ break;
+ case android.util.Log.WARN:
+ priorityStr = "WARN";
+ break;
+ case android.util.Log.ERROR:
+ priorityStr = "ERROR";
+ break;
+ case android.util.Log.ASSERT:
+ priorityStr = "ASSERT";
+ break;
+ default:
+ break;
+ }
+
+ // Handily, the Log class has a facility for converting a stack trace into a usable string.
+ String exceptionStr = null;
+ if (tr != null) {
+ exceptionStr = android.util.Log.getStackTraceString(tr);
+ }
+
+ // Take the priority, tag, message, and exception, and concatenate as necessary
+ // into one usable line of text.
+ final StringBuilder outputBuilder = new StringBuilder();
+
+ String delimiter = "\t";
+ appendIfNotNull(outputBuilder, priorityStr, delimiter);
+ appendIfNotNull(outputBuilder, tag, delimiter);
+ appendIfNotNull(outputBuilder, msg, delimiter);
+ appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+ // In case this was originally called from an AsyncTask or some other off-UI thread,
+ // make sure the update occurs within the UI thread.
+ ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+ @Override
+ public void run() {
+ // Display the text we just generated within the LogView.
+ appendToLog(outputBuilder.toString());
+ }
+ })));
+
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+ * the logger takes so many arguments that might be null, this method helps cut out some of the
+ * agonizing tedium of writing the same 3 lines over and over.
+ * @param source StringBuilder containing the text to append to.
+ * @param addStr The String to append
+ * @param delimiter The String to separate the source and appended strings. A tab or comma,
+ * for instance.
+ * @return The fully concatenated String as a StringBuilder
+ */
+ private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+ if (addStr != null) {
+ if (addStr.length() == 0) {
+ delimiter = "";
+ }
+
+ return source.append(addStr).append(delimiter);
+ }
+ return source;
+ }
+
+ // The next LogNode in the chain.
+ LogNode mNext;
+
+ /** Outputs the string as a new line of log data in the LogView. */
+ public void appendToLog(String s) {
+ append("\n" + s);
+ }
+
+
+}
diff --git a/samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/LogWrapper.java
new file mode 100644
index 000000000..16a9e7ba2
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * 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.example.android.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface. This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+ // For piping: The next node to receive Log data after this one has done its work.
+ private LogNode mNext;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /**
+ * Prints data out to the console using Android's native log mechanism.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ // There actually are log methods that don't take a msg parameter. For now,
+ // if that's the case, just convert null to the empty string and move on.
+ String useMsg = msg;
+ if (useMsg == null) {
+ useMsg = "";
+ }
+
+ // If an exeption was provided, convert that exception to a usable string and attach
+ // it to the end of the msg method.
+ if (tr != null) {
+ msg += "\n" + Log.getStackTraceString(tr);
+ }
+
+ // This is functionally identical to Log.x(tag, useMsg);
+ // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+ Log.println(priority, tag, useMsg);
+
+ // If this isn't the last node in the chain, move things along.
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+}
diff --git a/samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/MessageOnlyLogFilter.java
new file mode 100644
index 000000000..19967dcd4
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 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.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+ LogNode mNext;
+
+ /**
+ * Takes the "next" LogNode as a parameter, to simplify chaining.
+ *
+ * @param next The next LogNode in the pipeline.
+ */
+ public MessageOnlyLogFilter(LogNode next) {
+ mNext = next;
+ }
+
+ public MessageOnlyLogFilter() {
+ }
+
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ if (mNext != null) {
+ getNext().println(Log.NONE, null, msg, null);
+ }
+ }
+
+ /**
+ * Returns the next LogNode in the chain.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+}
diff --git a/samples/browseable/SlidingTabsColors/src/com.example.android.common/view/SlidingTabLayout.java b/samples/browseable/SlidingTabsColors/src/com.example.android.common/view/SlidingTabLayout.java
new file mode 100644
index 000000000..20049e335
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/src/com.example.android.common/view/SlidingTabLayout.java
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2013 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.example.android.common.view;
+
+import android.content.Context;
+import android.graphics.Typeface;
+import android.os.Build;
+import android.support.v4.view.PagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.HorizontalScrollView;
+import android.widget.TextView;
+
+/**
+ * To be used with ViewPager to provide a tab indicator component which give constant feedback as to
+ * the user's scroll progress.
+ * <p>
+ * To use the component, simply add it to your view hierarchy. Then in your
+ * {@link android.app.Activity} or {@link android.support.v4.app.Fragment} call
+ * {@link #setViewPager(ViewPager)} providing it the ViewPager this layout is being used for.
+ * <p>
+ * The colors can be customized in two ways. The first and simplest is to provide an array of colors
+ * via {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)}. The
+ * alternative is via the {@link TabColorizer} interface which provides you complete control over
+ * which color is used for any individual position.
+ * <p>
+ * The views used as tabs can be customized by calling {@link #setCustomTabView(int, int)},
+ * providing the layout ID of your custom layout.
+ */
+public class SlidingTabLayout extends HorizontalScrollView {
+
+ /**
+ * Allows complete control over the colors drawn in the tab layout. Set with
+ * {@link #setCustomTabColorizer(TabColorizer)}.
+ */
+ public interface TabColorizer {
+
+ /**
+ * @return return the color of the indicator used when {@code position} is selected.
+ */
+ int getIndicatorColor(int position);
+
+ /**
+ * @return return the color of the divider drawn to the right of {@code position}.
+ */
+ int getDividerColor(int position);
+
+ }
+
+ private static final int TITLE_OFFSET_DIPS = 24;
+ private static final int TAB_VIEW_PADDING_DIPS = 16;
+ private static final int TAB_VIEW_TEXT_SIZE_SP = 12;
+
+ private int mTitleOffset;
+
+ private int mTabViewLayoutId;
+ private int mTabViewTextViewId;
+
+ private ViewPager mViewPager;
+ private ViewPager.OnPageChangeListener mViewPagerPageChangeListener;
+
+ private final SlidingTabStrip mTabStrip;
+
+ public SlidingTabLayout(Context context) {
+ this(context, null);
+ }
+
+ public SlidingTabLayout(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public SlidingTabLayout(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ // Disable the Scroll Bar
+ setHorizontalScrollBarEnabled(false);
+ // Make sure that the Tab Strips fills this View
+ setFillViewport(true);
+
+ mTitleOffset = (int) (TITLE_OFFSET_DIPS * getResources().getDisplayMetrics().density);
+
+ mTabStrip = new SlidingTabStrip(context);
+ addView(mTabStrip, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+ }
+
+ /**
+ * Set the custom {@link TabColorizer} to be used.
+ *
+ * If you only require simple custmisation then you can use
+ * {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)} to achieve
+ * similar effects.
+ */
+ public void setCustomTabColorizer(TabColorizer tabColorizer) {
+ mTabStrip.setCustomTabColorizer(tabColorizer);
+ }
+
+ /**
+ * Sets the colors to be used for indicating the selected tab. These colors are treated as a
+ * circular array. Providing one color will mean that all tabs are indicated with the same color.
+ */
+ public void setSelectedIndicatorColors(int... colors) {
+ mTabStrip.setSelectedIndicatorColors(colors);
+ }
+
+ /**
+ * Sets the colors to be used for tab dividers. These colors are treated as a circular array.
+ * Providing one color will mean that all tabs are indicated with the same color.
+ */
+ public void setDividerColors(int... colors) {
+ mTabStrip.setDividerColors(colors);
+ }
+
+ /**
+ * Set the {@link ViewPager.OnPageChangeListener}. When using {@link SlidingTabLayout} you are
+ * required to set any {@link ViewPager.OnPageChangeListener} through this method. This is so
+ * that the layout can update it's scroll position correctly.
+ *
+ * @see ViewPager#setOnPageChangeListener(ViewPager.OnPageChangeListener)
+ */
+ public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
+ mViewPagerPageChangeListener = listener;
+ }
+
+ /**
+ * Set the custom layout to be inflated for the tab views.
+ *
+ * @param layoutResId Layout id to be inflated
+ * @param textViewId id of the {@link TextView} in the inflated view
+ */
+ public void setCustomTabView(int layoutResId, int textViewId) {
+ mTabViewLayoutId = layoutResId;
+ mTabViewTextViewId = textViewId;
+ }
+
+ /**
+ * Sets the associated view pager. Note that the assumption here is that the pager content
+ * (number of tabs and tab titles) does not change after this call has been made.
+ */
+ public void setViewPager(ViewPager viewPager) {
+ mTabStrip.removeAllViews();
+
+ mViewPager = viewPager;
+ if (viewPager != null) {
+ viewPager.setOnPageChangeListener(new InternalViewPagerListener());
+ populateTabStrip();
+ }
+ }
+
+ /**
+ * Create a default view to be used for tabs. This is called if a custom tab view is not set via
+ * {@link #setCustomTabView(int, int)}.
+ */
+ protected TextView createDefaultTabView(Context context) {
+ TextView textView = new TextView(context);
+ textView.setGravity(Gravity.CENTER);
+ textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, TAB_VIEW_TEXT_SIZE_SP);
+ textView.setTypeface(Typeface.DEFAULT_BOLD);
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ // If we're running on Honeycomb or newer, then we can use the Theme's
+ // selectableItemBackground to ensure that the View has a pressed state
+ TypedValue outValue = new TypedValue();
+ getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground,
+ outValue, true);
+ textView.setBackgroundResource(outValue.resourceId);
+ }
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ // If we're running on ICS or newer, enable all-caps to match the Action Bar tab style
+ textView.setAllCaps(true);
+ }
+
+ int padding = (int) (TAB_VIEW_PADDING_DIPS * getResources().getDisplayMetrics().density);
+ textView.setPadding(padding, padding, padding, padding);
+
+ return textView;
+ }
+
+ private void populateTabStrip() {
+ final PagerAdapter adapter = mViewPager.getAdapter();
+ final View.OnClickListener tabClickListener = new TabClickListener();
+
+ for (int i = 0; i < adapter.getCount(); i++) {
+ View tabView = null;
+ TextView tabTitleView = null;
+
+ if (mTabViewLayoutId != 0) {
+ // If there is a custom tab view layout id set, try and inflate it
+ tabView = LayoutInflater.from(getContext()).inflate(mTabViewLayoutId, mTabStrip,
+ false);
+ tabTitleView = (TextView) tabView.findViewById(mTabViewTextViewId);
+ }
+
+ if (tabView == null) {
+ tabView = createDefaultTabView(getContext());
+ }
+
+ if (tabTitleView == null && TextView.class.isInstance(tabView)) {
+ tabTitleView = (TextView) tabView;
+ }
+
+ tabTitleView.setText(adapter.getPageTitle(i));
+ tabView.setOnClickListener(tabClickListener);
+
+ mTabStrip.addView(tabView);
+ }
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ if (mViewPager != null) {
+ scrollToTab(mViewPager.getCurrentItem(), 0);
+ }
+ }
+
+ private void scrollToTab(int tabIndex, int positionOffset) {
+ final int tabStripChildCount = mTabStrip.getChildCount();
+ if (tabStripChildCount == 0 || tabIndex < 0 || tabIndex >= tabStripChildCount) {
+ return;
+ }
+
+ View selectedChild = mTabStrip.getChildAt(tabIndex);
+ if (selectedChild != null) {
+ int targetScrollX = selectedChild.getLeft() + positionOffset;
+
+ if (tabIndex > 0 || positionOffset > 0) {
+ // If we're not at the first child and are mid-scroll, make sure we obey the offset
+ targetScrollX -= mTitleOffset;
+ }
+
+ scrollTo(targetScrollX, 0);
+ }
+ }
+
+ private class InternalViewPagerListener implements ViewPager.OnPageChangeListener {
+ private int mScrollState;
+
+ @Override
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+ int tabStripChildCount = mTabStrip.getChildCount();
+ if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) {
+ return;
+ }
+
+ mTabStrip.onViewPagerPageChanged(position, positionOffset);
+
+ View selectedTitle = mTabStrip.getChildAt(position);
+ int extraOffset = (selectedTitle != null)
+ ? (int) (positionOffset * selectedTitle.getWidth())
+ : 0;
+ scrollToTab(position, extraOffset);
+
+ if (mViewPagerPageChangeListener != null) {
+ mViewPagerPageChangeListener.onPageScrolled(position, positionOffset,
+ positionOffsetPixels);
+ }
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int state) {
+ mScrollState = state;
+
+ if (mViewPagerPageChangeListener != null) {
+ mViewPagerPageChangeListener.onPageScrollStateChanged(state);
+ }
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ if (mScrollState == ViewPager.SCROLL_STATE_IDLE) {
+ mTabStrip.onViewPagerPageChanged(position, 0f);
+ scrollToTab(position, 0);
+ }
+
+ if (mViewPagerPageChangeListener != null) {
+ mViewPagerPageChangeListener.onPageSelected(position);
+ }
+ }
+
+ }
+
+ private class TabClickListener implements View.OnClickListener {
+ @Override
+ public void onClick(View v) {
+ for (int i = 0; i < mTabStrip.getChildCount(); i++) {
+ if (v == mTabStrip.getChildAt(i)) {
+ mViewPager.setCurrentItem(i);
+ return;
+ }
+ }
+ }
+ }
+
+}
diff --git a/samples/browseable/SlidingTabsColors/src/com.example.android.common/view/SlidingTabStrip.java b/samples/browseable/SlidingTabsColors/src/com.example.android.common/view/SlidingTabStrip.java
new file mode 100644
index 000000000..d5bbbae59
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/src/com.example.android.common/view/SlidingTabStrip.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2013 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.example.android.common.view;
+
+import android.R;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.View;
+import android.widget.LinearLayout;
+
+class SlidingTabStrip extends LinearLayout {
+
+ private static final int DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS = 2;
+ private static final byte DEFAULT_BOTTOM_BORDER_COLOR_ALPHA = 0x26;
+ private static final int SELECTED_INDICATOR_THICKNESS_DIPS = 8;
+ private static final int DEFAULT_SELECTED_INDICATOR_COLOR = 0xFF33B5E5;
+
+ private static final int DEFAULT_DIVIDER_THICKNESS_DIPS = 1;
+ private static final byte DEFAULT_DIVIDER_COLOR_ALPHA = 0x20;
+ private static final float DEFAULT_DIVIDER_HEIGHT = 0.5f;
+
+ private final int mBottomBorderThickness;
+ private final Paint mBottomBorderPaint;
+
+ private final int mSelectedIndicatorThickness;
+ private final Paint mSelectedIndicatorPaint;
+
+ private final int mDefaultBottomBorderColor;
+
+ private final Paint mDividerPaint;
+ private final float mDividerHeight;
+
+ private int mSelectedPosition;
+ private float mSelectionOffset;
+
+ private SlidingTabLayout.TabColorizer mCustomTabColorizer;
+ private final SimpleTabColorizer mDefaultTabColorizer;
+
+ SlidingTabStrip(Context context) {
+ this(context, null);
+ }
+
+ SlidingTabStrip(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setWillNotDraw(false);
+
+ final float density = getResources().getDisplayMetrics().density;
+
+ TypedValue outValue = new TypedValue();
+ context.getTheme().resolveAttribute(R.attr.colorForeground, outValue, true);
+ final int themeForegroundColor = outValue.data;
+
+ mDefaultBottomBorderColor = setColorAlpha(themeForegroundColor,
+ DEFAULT_BOTTOM_BORDER_COLOR_ALPHA);
+
+ mDefaultTabColorizer = new SimpleTabColorizer();
+ mDefaultTabColorizer.setIndicatorColors(DEFAULT_SELECTED_INDICATOR_COLOR);
+ mDefaultTabColorizer.setDividerColors(setColorAlpha(themeForegroundColor,
+ DEFAULT_DIVIDER_COLOR_ALPHA));
+
+ mBottomBorderThickness = (int) (DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS * density);
+ mBottomBorderPaint = new Paint();
+ mBottomBorderPaint.setColor(mDefaultBottomBorderColor);
+
+ mSelectedIndicatorThickness = (int) (SELECTED_INDICATOR_THICKNESS_DIPS * density);
+ mSelectedIndicatorPaint = new Paint();
+
+ mDividerHeight = DEFAULT_DIVIDER_HEIGHT;
+ mDividerPaint = new Paint();
+ mDividerPaint.setStrokeWidth((int) (DEFAULT_DIVIDER_THICKNESS_DIPS * density));
+ }
+
+ void setCustomTabColorizer(SlidingTabLayout.TabColorizer customTabColorizer) {
+ mCustomTabColorizer = customTabColorizer;
+ invalidate();
+ }
+
+ void setSelectedIndicatorColors(int... colors) {
+ // Make sure that the custom colorizer is removed
+ mCustomTabColorizer = null;
+ mDefaultTabColorizer.setIndicatorColors(colors);
+ invalidate();
+ }
+
+ void setDividerColors(int... colors) {
+ // Make sure that the custom colorizer is removed
+ mCustomTabColorizer = null;
+ mDefaultTabColorizer.setDividerColors(colors);
+ invalidate();
+ }
+
+ void onViewPagerPageChanged(int position, float positionOffset) {
+ mSelectedPosition = position;
+ mSelectionOffset = positionOffset;
+ invalidate();
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ final int height = getHeight();
+ final int childCount = getChildCount();
+ final int dividerHeightPx = (int) (Math.min(Math.max(0f, mDividerHeight), 1f) * height);
+ final SlidingTabLayout.TabColorizer tabColorizer = mCustomTabColorizer != null
+ ? mCustomTabColorizer
+ : mDefaultTabColorizer;
+
+ // Thick colored underline below the current selection
+ if (childCount > 0) {
+ View selectedTitle = getChildAt(mSelectedPosition);
+ int left = selectedTitle.getLeft();
+ int right = selectedTitle.getRight();
+ int color = tabColorizer.getIndicatorColor(mSelectedPosition);
+
+ if (mSelectionOffset > 0f && mSelectedPosition < (getChildCount() - 1)) {
+ int nextColor = tabColorizer.getIndicatorColor(mSelectedPosition + 1);
+ if (color != nextColor) {
+ color = blendColors(nextColor, color, mSelectionOffset);
+ }
+
+ // Draw the selection partway between the tabs
+ View nextTitle = getChildAt(mSelectedPosition + 1);
+ left = (int) (mSelectionOffset * nextTitle.getLeft() +
+ (1.0f - mSelectionOffset) * left);
+ right = (int) (mSelectionOffset * nextTitle.getRight() +
+ (1.0f - mSelectionOffset) * right);
+ }
+
+ mSelectedIndicatorPaint.setColor(color);
+
+ canvas.drawRect(left, height - mSelectedIndicatorThickness, right,
+ height, mSelectedIndicatorPaint);
+ }
+
+ // Thin underline along the entire bottom edge
+ canvas.drawRect(0, height - mBottomBorderThickness, getWidth(), height, mBottomBorderPaint);
+
+ // Vertical separators between the titles
+ int separatorTop = (height - dividerHeightPx) / 2;
+ for (int i = 0; i < childCount - 1; i++) {
+ View child = getChildAt(i);
+ mDividerPaint.setColor(tabColorizer.getDividerColor(i));
+ canvas.drawLine(child.getRight(), separatorTop, child.getRight(),
+ separatorTop + dividerHeightPx, mDividerPaint);
+ }
+ }
+
+ /**
+ * Set the alpha value of the {@code color} to be the given {@code alpha} value.
+ */
+ private static int setColorAlpha(int color, byte alpha) {
+ return Color.argb(alpha, Color.red(color), Color.green(color), Color.blue(color));
+ }
+
+ /**
+ * Blend {@code color1} and {@code color2} using the given ratio.
+ *
+ * @param ratio of which to blend. 1.0 will return {@code color1}, 0.5 will give an even blend,
+ * 0.0 will return {@code color2}.
+ */
+ private static int blendColors(int color1, int color2, float ratio) {
+ final float inverseRation = 1f - ratio;
+ float r = (Color.red(color1) * ratio) + (Color.red(color2) * inverseRation);
+ float g = (Color.green(color1) * ratio) + (Color.green(color2) * inverseRation);
+ float b = (Color.blue(color1) * ratio) + (Color.blue(color2) * inverseRation);
+ return Color.rgb((int) r, (int) g, (int) b);
+ }
+
+ private static class SimpleTabColorizer implements SlidingTabLayout.TabColorizer {
+ private int[] mIndicatorColors;
+ private int[] mDividerColors;
+
+ @Override
+ public final int getIndicatorColor(int position) {
+ return mIndicatorColors[position % mIndicatorColors.length];
+ }
+
+ @Override
+ public final int getDividerColor(int position) {
+ return mDividerColors[position % mDividerColors.length];
+ }
+
+ void setIndicatorColors(int... colors) {
+ mIndicatorColors = colors;
+ }
+
+ void setDividerColors(int... colors) {
+ mDividerColors = colors;
+ }
+ }
+} \ No newline at end of file
diff --git a/samples/browseable/SlidingTabsColors/src/com.example.android.slidingtabscolors/ContentFragment.java b/samples/browseable/SlidingTabsColors/src/com.example.android.slidingtabscolors/ContentFragment.java
new file mode 100644
index 000000000..4715fd728
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/src/com.example.android.slidingtabscolors/ContentFragment.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2013 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.example.android.slidingtabscolors;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+/**
+ * Simple Fragment used to display some meaningful content for each page in the sample's
+ * {@link android.support.v4.view.ViewPager}.
+ */
+public class ContentFragment extends Fragment {
+
+ private static final String KEY_TITLE = "title";
+ private static final String KEY_INDICATOR_COLOR = "indicator_color";
+ private static final String KEY_DIVIDER_COLOR = "divider_color";
+
+ /**
+ * @return a new instance of {@link ContentFragment}, adding the parameters into a bundle and
+ * setting them as arguments.
+ */
+ public static ContentFragment newInstance(CharSequence title, int indicatorColor,
+ int dividerColor) {
+ Bundle bundle = new Bundle();
+ bundle.putCharSequence(KEY_TITLE, title);
+ bundle.putInt(KEY_INDICATOR_COLOR, indicatorColor);
+ bundle.putInt(KEY_DIVIDER_COLOR, dividerColor);
+
+ ContentFragment fragment = new ContentFragment();
+ fragment.setArguments(bundle);
+
+ return fragment;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.pager_item, container, false);
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ Bundle args = getArguments();
+
+ if (args != null) {
+ TextView title = (TextView) view.findViewById(R.id.item_title);
+ title.setText("Title: " + args.getCharSequence(KEY_TITLE));
+
+ int indicatorColor = args.getInt(KEY_INDICATOR_COLOR);
+ TextView indicatorColorView = (TextView) view.findViewById(R.id.item_indicator_color);
+ indicatorColorView.setText("Indicator: #" + Integer.toHexString(indicatorColor));
+ indicatorColorView.setTextColor(indicatorColor);
+
+ int dividerColor = args.getInt(KEY_DIVIDER_COLOR);
+ TextView dividerColorView = (TextView) view.findViewById(R.id.item_divider_color);
+ dividerColorView.setText("Divider: #" + Integer.toHexString(dividerColor));
+ dividerColorView.setTextColor(dividerColor);
+ }
+ }
+}
diff --git a/samples/browseable/SlidingTabsColors/src/com.example.android.slidingtabscolors/MainActivity.java b/samples/browseable/SlidingTabsColors/src/com.example.android.slidingtabscolors/MainActivity.java
new file mode 100644
index 000000000..d3d7567cd
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/src/com.example.android.slidingtabscolors/MainActivity.java
@@ -0,0 +1,110 @@
+/*
+* Copyright 2013 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.example.android.slidingtabscolors;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.ViewAnimator;
+
+import com.example.android.common.activities.SampleActivityBase;
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogFragment;
+import com.example.android.common.logger.LogWrapper;
+import com.example.android.common.logger.MessageOnlyLogFilter;
+
+/**
+ * A simple launcher activity containing a summary sample description, sample log and a custom
+ * {@link android.support.v4.app.Fragment} which can display a view.
+ * <p>
+ * For devices with displays with a width of 720dp or greater, the sample log is always visible,
+ * on other devices it's visibility is controlled by an item on the Action Bar.
+ */
+public class MainActivity extends SampleActivityBase {
+
+ public static final String TAG = "MainActivity";
+
+ // Whether the Log Fragment is currently shown
+ private boolean mLogShown;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+ SlidingTabsColorsFragment fragment = new SlidingTabsColorsFragment();
+ transaction.replace(R.id.sample_content_fragment, fragment);
+ transaction.commit();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.main, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ MenuItem logToggle = menu.findItem(R.id.menu_toggle_log);
+ logToggle.setVisible(findViewById(R.id.sample_output) instanceof ViewAnimator);
+ logToggle.setTitle(mLogShown ? R.string.sample_hide_log : R.string.sample_show_log);
+
+ return super.onPrepareOptionsMenu(menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch(item.getItemId()) {
+ case R.id.menu_toggle_log:
+ mLogShown = !mLogShown;
+ ViewAnimator output = (ViewAnimator) findViewById(R.id.sample_output);
+ if (mLogShown) {
+ output.setDisplayedChild(1);
+ } else {
+ output.setDisplayedChild(0);
+ }
+ supportInvalidateOptionsMenu();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ /** Create a chain of targets that will receive log data */
+ @Override
+ public void initializeLogging() {
+ // Wraps Android's native log framework.
+ LogWrapper logWrapper = new LogWrapper();
+ // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+ Log.setLogNode(logWrapper);
+
+ // Filter strips out everything except the message text.
+ MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
+ logWrapper.setNext(msgFilter);
+
+ // On screen logging via a fragment with a TextView.
+ LogFragment logFragment = (LogFragment) getSupportFragmentManager()
+ .findFragmentById(R.id.log_fragment);
+ msgFilter.setNext(logFragment.getLogView());
+
+ Log.i(TAG, "Ready");
+ }
+}
diff --git a/samples/browseable/SlidingTabsColors/src/com.example.android.slidingtabscolors/SlidingTabsColorsFragment.java b/samples/browseable/SlidingTabsColors/src/com.example.android.slidingtabscolors/SlidingTabsColorsFragment.java
new file mode 100644
index 000000000..1e5c3e39d
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/src/com.example.android.slidingtabscolors/SlidingTabsColorsFragment.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright 2013 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.example.android.slidingtabscolors;
+
+import com.example.android.common.view.SlidingTabLayout;
+
+import android.graphics.Color;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentPagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A basic sample which shows how to use {@link com.example.android.common.view.SlidingTabLayout}
+ * to display a custom {@link ViewPager} title strip which gives continuous feedback to the user
+ * when scrolling.
+ */
+public class SlidingTabsColorsFragment extends Fragment {
+
+ /**
+ * This class represents a tab to be displayed by {@link ViewPager} and it's associated
+ * {@link SlidingTabLayout}.
+ */
+ static class SamplePagerItem {
+ private final CharSequence mTitle;
+ private final int mIndicatorColor;
+ private final int mDividerColor;
+
+ SamplePagerItem(CharSequence title, int indicatorColor, int dividerColor) {
+ mTitle = title;
+ mIndicatorColor = indicatorColor;
+ mDividerColor = dividerColor;
+ }
+
+ /**
+ * @return A new {@link Fragment} to be displayed by a {@link ViewPager}
+ */
+ Fragment createFragment() {
+ return ContentFragment.newInstance(mTitle, mIndicatorColor, mDividerColor);
+ }
+
+ /**
+ * @return the title which represents this tab. In this sample this is used directly by
+ * {@link android.support.v4.view.PagerAdapter#getPageTitle(int)}
+ */
+ CharSequence getTitle() {
+ return mTitle;
+ }
+
+ /**
+ * @return the color to be used for indicator on the {@link SlidingTabLayout}
+ */
+ int getIndicatorColor() {
+ return mIndicatorColor;
+ }
+
+ /**
+ * @return the color to be used for right divider on the {@link SlidingTabLayout}
+ */
+ int getDividerColor() {
+ return mDividerColor;
+ }
+ }
+
+ static final String LOG_TAG = "SlidingTabsColorsFragment";
+
+ /**
+ * A custom {@link ViewPager} title strip which looks much like Tabs present in Android v4.0 and
+ * above, but is designed to give continuous feedback to the user when scrolling.
+ */
+ private SlidingTabLayout mSlidingTabLayout;
+
+ /**
+ * A {@link ViewPager} which will be used in conjunction with the {@link SlidingTabLayout} above.
+ */
+ private ViewPager mViewPager;
+
+ /**
+ * List of {@link SamplePagerItem} which represent this sample's tabs.
+ */
+ private List<SamplePagerItem> mTabs = new ArrayList<SamplePagerItem>();
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // BEGIN_INCLUDE (populate_tabs)
+ /**
+ * Populate our tab list with tabs. Each item contains a title, indicator color and divider
+ * color, which are used by {@link SlidingTabLayout}.
+ */
+ mTabs.add(new SamplePagerItem(
+ getString(R.string.tab_stream), // Title
+ Color.BLUE, // Indicator color
+ Color.GRAY // Divider color
+ ));
+
+ mTabs.add(new SamplePagerItem(
+ getString(R.string.tab_messages), // Title
+ Color.RED, // Indicator color
+ Color.GRAY // Divider color
+ ));
+
+ mTabs.add(new SamplePagerItem(
+ getString(R.string.tab_photos), // Title
+ Color.YELLOW, // Indicator color
+ Color.GRAY // Divider color
+ ));
+
+ mTabs.add(new SamplePagerItem(
+ getString(R.string.tab_notifications), // Title
+ Color.GREEN, // Indicator color
+ Color.GRAY // Divider color
+ ));
+ // END_INCLUDE (populate_tabs)
+ }
+
+ /**
+ * Inflates the {@link View} which will be displayed by this {@link Fragment}, from the app's
+ * resources.
+ */
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fragment_sample, container, false);
+ }
+
+ // BEGIN_INCLUDE (fragment_onviewcreated)
+ /**
+ * This is called after the {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)} has finished.
+ * Here we can pick out the {@link View}s we need to configure from the content view.
+ *
+ * We set the {@link ViewPager}'s adapter to be an instance of
+ * {@link SampleFragmentPagerAdapter}. The {@link SlidingTabLayout} is then given the
+ * {@link ViewPager} so that it can populate itself.
+ *
+ * @param view View created in {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}
+ */
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ // BEGIN_INCLUDE (setup_viewpager)
+ // Get the ViewPager and set it's PagerAdapter so that it can display items
+ mViewPager = (ViewPager) view.findViewById(R.id.viewpager);
+ mViewPager.setAdapter(new SampleFragmentPagerAdapter(getChildFragmentManager()));
+ // END_INCLUDE (setup_viewpager)
+
+ // BEGIN_INCLUDE (setup_slidingtablayout)
+ // Give the SlidingTabLayout the ViewPager, this must be done AFTER the ViewPager has had
+ // it's PagerAdapter set.
+ mSlidingTabLayout = (SlidingTabLayout) view.findViewById(R.id.sliding_tabs);
+ mSlidingTabLayout.setViewPager(mViewPager);
+
+ // BEGIN_INCLUDE (tab_colorizer)
+ // Set a TabColorizer to customize the indicator and divider colors. Here we just retrieve
+ // the tab at the position, and return it's set color
+ mSlidingTabLayout.setCustomTabColorizer(new SlidingTabLayout.TabColorizer() {
+
+ @Override
+ public int getIndicatorColor(int position) {
+ return mTabs.get(position).getIndicatorColor();
+ }
+
+ @Override
+ public int getDividerColor(int position) {
+ return mTabs.get(position).getDividerColor();
+ }
+
+ });
+ // END_INCLUDE (tab_colorizer)
+ // END_INCLUDE (setup_slidingtablayout)
+ }
+ // END_INCLUDE (fragment_onviewcreated)
+
+ /**
+ * The {@link FragmentPagerAdapter} used to display pages in this sample. The individual pages
+ * are instances of {@link ContentFragment} which just display three lines of text. Each page is
+ * created by the relevant {@link SamplePagerItem} for the requested position.
+ * <p>
+ * The important section of this class is the {@link #getPageTitle(int)} method which controls
+ * what is displayed in the {@link SlidingTabLayout}.
+ */
+ class SampleFragmentPagerAdapter extends FragmentPagerAdapter {
+
+ SampleFragmentPagerAdapter(FragmentManager fm) {
+ super(fm);
+ }
+
+ /**
+ * Return the {@link android.support.v4.app.Fragment} to be displayed at {@code position}.
+ * <p>
+ * Here we return the value returned from {@link SamplePagerItem#createFragment()}.
+ */
+ @Override
+ public Fragment getItem(int i) {
+ return mTabs.get(i).createFragment();
+ }
+
+ @Override
+ public int getCount() {
+ return mTabs.size();
+ }
+
+ // BEGIN_INCLUDE (pageradapter_getpagetitle)
+ /**
+ * Return the title of the item at {@code position}. This is important as what this method
+ * returns is what is displayed in the {@link SlidingTabLayout}.
+ * <p>
+ * Here we return the value returned from {@link SamplePagerItem#getTitle()}.
+ */
+ @Override
+ public CharSequence getPageTitle(int position) {
+ return mTabs.get(position).getTitle();
+ }
+ // END_INCLUDE (pageradapter_getpagetitle)
+
+ }
+
+} \ No newline at end of file
diff --git a/samples/browseable/StorageClient/res/values-sw600dp/template-dimens.xml b/samples/browseable/StorageClient/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 000000000..22074a2bd
--- /dev/null
+++ b/samples/browseable/StorageClient/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/StorageClient/res/values-sw600dp/template-styles.xml b/samples/browseable/StorageClient/res/values-sw600dp/template-styles.xml
new file mode 100644
index 000000000..03d197418
--- /dev/null
+++ b/samples/browseable/StorageClient/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceLarge</item>
+ <item name="android:lineSpacingMultiplier">1.2</item>
+ <item name="android:shadowDy">-6.5</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/StorageClient/res/values/template-dimens.xml b/samples/browseable/StorageClient/res/values/template-dimens.xml
new file mode 100644
index 000000000..39e710b5c
--- /dev/null
+++ b/samples/browseable/StorageClient/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/StorageClient/res/values/styles.xml b/samples/browseable/StorageClient/res/values/template-styles.xml
index d3f82ff64..d3f82ff64 100644
--- a/samples/browseable/StorageClient/res/values/styles.xml
+++ b/samples/browseable/StorageClient/res/values/template-styles.xml
diff --git a/samples/browseable/TextLinkify/res/values-sw600dp/template-dimens.xml b/samples/browseable/TextLinkify/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 000000000..22074a2bd
--- /dev/null
+++ b/samples/browseable/TextLinkify/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/TextLinkify/res/values-sw600dp/template-styles.xml b/samples/browseable/TextLinkify/res/values-sw600dp/template-styles.xml
new file mode 100644
index 000000000..03d197418
--- /dev/null
+++ b/samples/browseable/TextLinkify/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceLarge</item>
+ <item name="android:lineSpacingMultiplier">1.2</item>
+ <item name="android:shadowDy">-6.5</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/TextLinkify/res/values/dimens.xml b/samples/browseable/TextLinkify/res/values/dimens.xml
index 39e710b5c..3b1975a06 100644
--- a/samples/browseable/TextLinkify/res/values/dimens.xml
+++ b/samples/browseable/TextLinkify/res/values/dimens.xml
@@ -5,28 +5,19 @@
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
+ http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
- -->
+-->
<resources>
- <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
-
- <dimen name="margin_tiny">4dp</dimen>
- <dimen name="margin_small">8dp</dimen>
- <dimen name="margin_medium">16dp</dimen>
- <dimen name="margin_large">32dp</dimen>
- <dimen name="margin_huge">64dp</dimen>
-
- <!-- Semantic definitions -->
-
- <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
- <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+ <!-- Default screen margins, per the Android Design guidelines. -->
+ <dimen name="activity_horizontal_margin">16dp</dimen>
+ <dimen name="activity_vertical_margin">16dp</dimen>
</resources>
diff --git a/samples/browseable/TextLinkify/res/values/styles.xml b/samples/browseable/TextLinkify/res/values/styles.xml
index 404623e3d..29c423067 100644
--- a/samples/browseable/TextLinkify/res/values/styles.xml
+++ b/samples/browseable/TextLinkify/res/values/styles.xml
@@ -5,38 +5,18 @@
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
+ http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
- -->
+-->
-<resources>
-
- <!-- Activity themes -->
-
- <style name="Theme.Base" parent="android:Theme.Holo.Light" />
-
- <style name="Theme.Sample" parent="Theme.Base" />
-
- <style name="AppTheme" parent="Theme.Sample" />
- <!-- Widget styling -->
-
- <style name="Widget" />
-
- <style name="Widget.SampleMessage">
- <item name="android:textAppearance">?android:textAppearanceMedium</item>
- <item name="android:lineSpacingMultiplier">1.1</item>
- </style>
-
- <style name="Widget.SampleMessageTile">
- <item name="android:background">@drawable/tile</item>
- <item name="android:shadowColor">#7F000000</item>
- <item name="android:shadowDy">-3.5</item>
- <item name="android:shadowRadius">2</item>
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <style name="LinkText">
+ <item name="android:paddingTop">9dp</item>
+ <item name="android:paddingBottom">9dp</item>
</style>
-
</resources>
diff --git a/samples/browseable/TextLinkify/res/values/template-dimens.xml b/samples/browseable/TextLinkify/res/values/template-dimens.xml
new file mode 100644
index 000000000..39e710b5c
--- /dev/null
+++ b/samples/browseable/TextLinkify/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/TextLinkify/res/values/template-styles.xml b/samples/browseable/TextLinkify/res/values/template-styles.xml
new file mode 100644
index 000000000..404623e3d
--- /dev/null
+++ b/samples/browseable/TextLinkify/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/TextSwitcher/res/values-sw600dp/dimens.xml b/samples/browseable/TextSwitcher/res/values-sw600dp/dimens.xml
index 22074a2bd..686fe8915 100644
--- a/samples/browseable/TextSwitcher/res/values-sw600dp/dimens.xml
+++ b/samples/browseable/TextSwitcher/res/values-sw600dp/dimens.xml
@@ -5,20 +5,20 @@
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
+ http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
- -->
+-->
<resources>
- <!-- Semantic definitions -->
-
- <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
- <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+ <!--
+ Customize dimensions originally defined in res/values/dimens.xml (such as
+ screen margins) for sw600dp devices (e.g. 7" tablets) here.
+ -->
</resources>
diff --git a/samples/browseable/TextSwitcher/res/values-sw600dp/template-dimens.xml b/samples/browseable/TextSwitcher/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 000000000..22074a2bd
--- /dev/null
+++ b/samples/browseable/TextSwitcher/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/TextSwitcher/res/values-sw600dp/template-styles.xml b/samples/browseable/TextSwitcher/res/values-sw600dp/template-styles.xml
new file mode 100644
index 000000000..03d197418
--- /dev/null
+++ b/samples/browseable/TextSwitcher/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceLarge</item>
+ <item name="android:lineSpacingMultiplier">1.2</item>
+ <item name="android:shadowDy">-6.5</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/TextSwitcher/res/values/dimens.xml b/samples/browseable/TextSwitcher/res/values/dimens.xml
index 39e710b5c..3b1975a06 100644
--- a/samples/browseable/TextSwitcher/res/values/dimens.xml
+++ b/samples/browseable/TextSwitcher/res/values/dimens.xml
@@ -5,28 +5,19 @@
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
+ http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
- -->
+-->
<resources>
- <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
-
- <dimen name="margin_tiny">4dp</dimen>
- <dimen name="margin_small">8dp</dimen>
- <dimen name="margin_medium">16dp</dimen>
- <dimen name="margin_large">32dp</dimen>
- <dimen name="margin_huge">64dp</dimen>
-
- <!-- Semantic definitions -->
-
- <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
- <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+ <!-- Default screen margins, per the Android Design guidelines. -->
+ <dimen name="activity_horizontal_margin">16dp</dimen>
+ <dimen name="activity_vertical_margin">16dp</dimen>
</resources>
diff --git a/samples/browseable/TextSwitcher/res/values/template-dimens.xml b/samples/browseable/TextSwitcher/res/values/template-dimens.xml
new file mode 100644
index 000000000..39e710b5c
--- /dev/null
+++ b/samples/browseable/TextSwitcher/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/TextSwitcher/res/values/template-styles.xml b/samples/browseable/TextSwitcher/res/values/template-styles.xml
new file mode 100644
index 000000000..404623e3d
--- /dev/null
+++ b/samples/browseable/TextSwitcher/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/repeatingAlarm/_index.jd b/samples/browseable/repeatingAlarm/_index.jd
deleted file mode 100644
index bd77d6c27..000000000
--- a/samples/browseable/repeatingAlarm/_index.jd
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-page.tags="RepeatingAlarm"
-sample.group=Background
-@jd:body
-
-<p>This sample demonstrates how to implement a repeating alarm using an
-{@link android.app.AlarmManager}.</p>
diff --git a/samples/browseable/repeatingAlarm/res/values/styles.xml b/samples/browseable/repeatingAlarm/res/values/styles.xml
deleted file mode 100644
index d3f82ff64..000000000
--- a/samples/browseable/repeatingAlarm/res/values/styles.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<!--
- Copyright 2013 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<resources>
-
- <!-- Activity themes -->
-
- <style name="Theme.Base" parent="android:Theme.Holo.Light" />
-
- <style name="AppTheme" parent="Theme.Base" />
- <!-- Widget styling -->
-
- <style name="Widget" />
-
- <style name="Widget.SampleMessage">
- <item name="android:textAppearance">?android:textAppearanceMedium</item>
- <item name="android:lineSpacingMultiplier">1.1</item>
- </style>
-
- <style name="Widget.SampleMessageTile">
- <item name="android:background">@drawable/tile</item>
- <item name="android:shadowColor">#7F000000</item>
- <item name="android:shadowDy">-3.5</item>
- <item name="android:shadowRadius">2</item>
- </style>
-
-
- <style name="Widget.SampleOutput">
- <item name="android:padding">@dimen/margin_medium</item>
- <item name="android:textAppearance">?android:textAppearanceMedium</item>
- <item name="android:lineSpacingMultiplier">1.1</item>
- </style>
-
- <style name="Log" parent="Widget.SampleOutput">
- <item name="android:typeface">monospace</item>
- </style>
-
-</resources>