diff --git a/samples/training/bitmapfun/BitmapFun/build.gradle b/samples/training/bitmapfun/BitmapFun/build.gradle
deleted file mode 100644
index c9782314d..000000000
--- a/samples/training/bitmapfun/BitmapFun/build.gradle
+++ /dev/null
@@ -1,27 +0,0 @@
-buildscript {
- repositories {
- mavenCentral()
- }
- dependencies {
- classpath 'com.android.tools.build:gradle:0.6.+'
- }
-}
-apply plugin: 'android'
-
-repositories {
- mavenCentral()
-}
-
-android {
- compileSdkVersion 19
- buildToolsVersion "19.0.0"
-
- defaultConfig {
- minSdkVersion 7
- targetSdkVersion 19
- }
-}
-
-dependencies {
- compile 'com.android.support:support-v4:19.0.+'
-}
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/AndroidManifest.xml b/samples/training/bitmapfun/BitmapFun/src/main/AndroidManifest.xml
deleted file mode 100644
index 9ca5cf50c..000000000
--- a/samples/training/bitmapfun/BitmapFun/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/provider/Images.java b/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/provider/Images.java
deleted file mode 100644
index fcf4496bd..000000000
--- a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/provider/Images.java
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * 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.bitmapfun.provider;
-
-/**
- * Some simple test data to use for this sample app.
- */
-public class Images {
-
- /**
- * This are PicasaWeb URLs and could potentially change. Ideally the PicasaWeb API should be
- * used to fetch the URLs.
- *
- * Credit to Romain Guy for the photos:
- * http://www.curious-creature.org/
- * https://plus.google.com/109538161516040592207/about
- * http://www.flickr.com/photos/romainguy
- */
- public final static String[] imageUrls = new String[] {
- "https://lh6.googleusercontent.com/-55osAWw3x0Q/URquUtcFr5I/AAAAAAAAAbs/rWlj1RUKrYI/s1024/A%252520Photographer.jpg",
- "https://lh4.googleusercontent.com/--dq8niRp7W4/URquVgmXvgI/AAAAAAAAAbs/-gnuLQfNnBA/s1024/A%252520Song%252520of%252520Ice%252520and%252520Fire.jpg",
- "https://lh5.googleusercontent.com/-7qZeDtRKFKc/URquWZT1gOI/AAAAAAAAAbs/hqWgteyNXsg/s1024/Another%252520Rockaway%252520Sunset.jpg",
- "https://lh3.googleusercontent.com/--L0Km39l5J8/URquXHGcdNI/AAAAAAAAAbs/3ZrSJNrSomQ/s1024/Antelope%252520Butte.jpg",
- "https://lh6.googleusercontent.com/-8HO-4vIFnlw/URquZnsFgtI/AAAAAAAAAbs/WT8jViTF7vw/s1024/Antelope%252520Hallway.jpg",
- "https://lh4.googleusercontent.com/-WIuWgVcU3Qw/URqubRVcj4I/AAAAAAAAAbs/YvbwgGjwdIQ/s1024/Antelope%252520Walls.jpg",
- "https://lh6.googleusercontent.com/-UBmLbPELvoQ/URqucCdv0kI/AAAAAAAAAbs/IdNhr2VQoQs/s1024/Apre%2525CC%252580s%252520la%252520Pluie.jpg",
- "https://lh3.googleusercontent.com/-s-AFpvgSeew/URquc6dF-JI/AAAAAAAAAbs/Mt3xNGRUd68/s1024/Backlit%252520Cloud.jpg",
- "https://lh5.googleusercontent.com/-bvmif9a9YOQ/URquea3heHI/AAAAAAAAAbs/rcr6wyeQtAo/s1024/Bee%252520and%252520Flower.jpg",
- "https://lh5.googleusercontent.com/-n7mdm7I7FGs/URqueT_BT-I/AAAAAAAAAbs/9MYmXlmpSAo/s1024/Bonzai%252520Rock%252520Sunset.jpg",
- "https://lh6.googleusercontent.com/-4CN4X4t0M1k/URqufPozWzI/AAAAAAAAAbs/8wK41lg1KPs/s1024/Caterpillar.jpg",
- "https://lh3.googleusercontent.com/-rrFnVC8xQEg/URqufdrLBaI/AAAAAAAAAbs/s69WYy_fl1E/s1024/Chess.jpg",
- "https://lh5.googleusercontent.com/-WVpRptWH8Yw/URqugh-QmDI/AAAAAAAAAbs/E-MgBgtlUWU/s1024/Chihuly.jpg",
- "https://lh5.googleusercontent.com/-0BDXkYmckbo/URquhKFW84I/AAAAAAAAAbs/ogQtHCTk2JQ/s1024/Closed%252520Door.jpg",
- "https://lh3.googleusercontent.com/-PyggXXZRykM/URquh-kVvoI/AAAAAAAAAbs/hFtDwhtrHHQ/s1024/Colorado%252520River%252520Sunset.jpg",
- "https://lh3.googleusercontent.com/-ZAs4dNZtALc/URquikvOCWI/AAAAAAAAAbs/DXz4h3dll1Y/s1024/Colors%252520of%252520Autumn.jpg",
- "https://lh4.googleusercontent.com/-GztnWEIiMz8/URqukVCU7bI/AAAAAAAAAbs/jo2Hjv6MZ6M/s1024/Countryside.jpg",
- "https://lh4.googleusercontent.com/-bEg9EZ9QoiM/URquklz3FGI/AAAAAAAAAbs/UUuv8Ac2BaE/s1024/Death%252520Valley%252520-%252520Dunes.jpg",
- "https://lh6.googleusercontent.com/-ijQJ8W68tEE/URqulGkvFEI/AAAAAAAAAbs/zPXvIwi_rFw/s1024/Delicate%252520Arch.jpg",
- "https://lh5.googleusercontent.com/-Oh8mMy2ieng/URqullDwehI/AAAAAAAAAbs/TbdeEfsaIZY/s1024/Despair.jpg",
- "https://lh5.googleusercontent.com/-gl0y4UiAOlk/URqumC_KjBI/AAAAAAAAAbs/PM1eT7dn4oo/s1024/Eagle%252520Fall%252520Sunrise.jpg",
- "https://lh3.googleusercontent.com/-hYYHd2_vXPQ/URqumtJa9eI/AAAAAAAAAbs/wAalXVkbSh0/s1024/Electric%252520Storm.jpg",
- "https://lh5.googleusercontent.com/-PyY_yiyjPTo/URqunUOhHFI/AAAAAAAAAbs/azZoULNuJXc/s1024/False%252520Kiva.jpg",
- "https://lh6.googleusercontent.com/-PYvLVdvXywk/URqunwd8hfI/AAAAAAAAAbs/qiMwgkFvf6I/s1024/Fitzgerald%252520Streaks.jpg",
- "https://lh4.googleusercontent.com/-KIR_UobIIqY/URquoCZ9SlI/AAAAAAAAAbs/Y4d4q8sXu4c/s1024/Foggy%252520Sunset.jpg",
- "https://lh6.googleusercontent.com/-9lzOk_OWZH0/URquoo4xYoI/AAAAAAAAAbs/AwgzHtNVCwU/s1024/Frantic.jpg",
- "https://lh3.googleusercontent.com/-0X3JNaKaz48/URqupH78wpI/AAAAAAAAAbs/lHXxu_zbH8s/s1024/Golden%252520Gate%252520Afternoon.jpg",
- "https://lh6.googleusercontent.com/-95sb5ag7ABc/URqupl95RDI/AAAAAAAAAbs/g73R20iVTRA/s1024/Golden%252520Gate%252520Fog.jpg",
- "https://lh3.googleusercontent.com/-JB9v6rtgHhk/URqup21F-zI/AAAAAAAAAbs/64Fb8qMZWXk/s1024/Golden%252520Grass.jpg",
- "https://lh4.googleusercontent.com/-EIBGfnuLtII/URquqVHwaRI/AAAAAAAAAbs/FA4McV2u8VE/s1024/Grand%252520Teton.jpg",
- "https://lh4.googleusercontent.com/-WoMxZvmN9nY/URquq1v2AoI/AAAAAAAAAbs/grj5uMhL6NA/s1024/Grass%252520Closeup.jpg",
- "https://lh3.googleusercontent.com/-6hZiEHXx64Q/URqurxvNdqI/AAAAAAAAAbs/kWMXM3o5OVI/s1024/Green%252520Grass.jpg",
- "https://lh5.googleusercontent.com/-6LVb9OXtQ60/URquteBFuKI/AAAAAAAAAbs/4F4kRgecwFs/s1024/Hanging%252520Leaf.jpg",
- "https://lh4.googleusercontent.com/-zAvf__52ONk/URqutT_IuxI/AAAAAAAAAbs/D_bcuc0thoU/s1024/Highway%2525201.jpg",
- "https://lh6.googleusercontent.com/-H4SrUg615rA/URquuL27fXI/AAAAAAAAAbs/4aEqJfiMsOU/s1024/Horseshoe%252520Bend%252520Sunset.jpg",
- "https://lh4.googleusercontent.com/-JhFi4fb_Pqw/URquuX-QXbI/AAAAAAAAAbs/IXpYUxuweYM/s1024/Horseshoe%252520Bend.jpg",
- "https://lh5.googleusercontent.com/-UGgssvFRJ7g/URquueyJzGI/AAAAAAAAAbs/yYIBlLT0toM/s1024/Into%252520the%252520Blue.jpg",
- "https://lh3.googleusercontent.com/-CH7KoupI7uI/URquu0FF__I/AAAAAAAAAbs/R7GDmI7v_G0/s1024/Jelly%252520Fish%2525202.jpg",
- "https://lh4.googleusercontent.com/-pwuuw6yhg8U/URquvPxR3FI/AAAAAAAAAbs/VNGk6f-tsGE/s1024/Jelly%252520Fish%2525203.jpg",
- "https://lh5.googleusercontent.com/-GoUQVw1fnFw/URquv6xbC0I/AAAAAAAAAbs/zEUVTQQ43Zc/s1024/Kauai.jpg",
- "https://lh6.googleusercontent.com/-8QdYYQEpYjw/URquwvdh88I/AAAAAAAAAbs/cktDy-ysfHo/s1024/Kyoto%252520Sunset.jpg",
- "https://lh4.googleusercontent.com/-vPeekyDjOE0/URquwzJ28qI/AAAAAAAAAbs/qxcyXULsZrg/s1024/Lake%252520Tahoe%252520Colors.jpg",
- "https://lh4.googleusercontent.com/-xBPxWpD4yxU/URquxWHk8AI/AAAAAAAAAbs/ARDPeDYPiMY/s1024/Lava%252520from%252520the%252520Sky.jpg",
- "https://lh3.googleusercontent.com/-897VXrJB6RE/URquxxxd-5I/AAAAAAAAAbs/j-Cz4T4YvIw/s1024/Leica%25252050mm%252520Summilux.jpg",
- "https://lh5.googleusercontent.com/-qSJ4D4iXzGo/URquyDWiJ1I/AAAAAAAAAbs/k2pBXeWehOA/s1024/Leica%25252050mm%252520Summilux.jpg",
- "https://lh6.googleusercontent.com/-dwlPg83vzLg/URquylTVuFI/AAAAAAAAAbs/G6SyQ8b4YsI/s1024/Leica%252520M8%252520%252528Front%252529.jpg",
- "https://lh3.googleusercontent.com/-R3_EYAyJvfk/URquzQBv8eI/AAAAAAAAAbs/b9xhpUM3pEI/s1024/Light%252520to%252520Sand.jpg",
- "https://lh3.googleusercontent.com/-fHY5h67QPi0/URqu0Cp4J1I/AAAAAAAAAbs/0lG6m94Z6vM/s1024/Little%252520Bit%252520of%252520Paradise.jpg",
- "https://lh5.googleusercontent.com/-TzF_LwrCnRM/URqu0RddPOI/AAAAAAAAAbs/gaj2dLiuX0s/s1024/Lone%252520Pine%252520Sunset.jpg",
- "https://lh3.googleusercontent.com/-4HdpJ4_DXU4/URqu046dJ9I/AAAAAAAAAbs/eBOodtk2_uk/s1024/Lonely%252520Rock.jpg",
- "https://lh6.googleusercontent.com/-erbF--z-W4s/URqu1ajSLkI/AAAAAAAAAbs/xjDCDO1INzM/s1024/Longue%252520Vue.jpg",
- "https://lh6.googleusercontent.com/-0CXJRdJaqvc/URqu1opNZNI/AAAAAAAAAbs/PFB2oPUU7Lk/s1024/Look%252520Me%252520in%252520the%252520Eye.jpg",
- "https://lh3.googleusercontent.com/-D_5lNxnDN6g/URqu2Tk7HVI/AAAAAAAAAbs/p0ddca9W__Y/s1024/Lost%252520in%252520a%252520Field.jpg",
- "https://lh6.googleusercontent.com/-flsqwMrIk2Q/URqu24PcmjI/AAAAAAAAAbs/5ocIH85XofM/s1024/Marshall%252520Beach%252520Sunset.jpg",
- "https://lh4.googleusercontent.com/-Y4lgryEVTmU/URqu28kG3gI/AAAAAAAAAbs/OjXpekqtbJ4/s1024/Mono%252520Lake%252520Blue.jpg",
- "https://lh4.googleusercontent.com/-AaHAJPmcGYA/URqu3PIldHI/AAAAAAAAAbs/lcTqk1SIcRs/s1024/Monument%252520Valley%252520Overlook.jpg",
- "https://lh4.googleusercontent.com/-vKxfdQ83dQA/URqu31Yq_BI/AAAAAAAAAbs/OUoGk_2AyfM/s1024/Moving%252520Rock.jpg",
- "https://lh5.googleusercontent.com/-CG62QiPpWXg/URqu4ia4vRI/AAAAAAAAAbs/0YOdqLAlcAc/s1024/Napali%252520Coast.jpg",
- "https://lh6.googleusercontent.com/-wdGrP5PMmJQ/URqu5PZvn7I/AAAAAAAAAbs/m0abEcdPXe4/s1024/One%252520Wheel.jpg",
- "https://lh6.googleusercontent.com/-6WS5DoCGuOA/URqu5qx1UgI/AAAAAAAAAbs/giMw2ixPvrY/s1024/Open%252520Sky.jpg",
- "https://lh6.googleusercontent.com/-u8EHKj8G8GQ/URqu55sM6yI/AAAAAAAAAbs/lIXX_GlTdmI/s1024/Orange%252520Sunset.jpg",
- "https://lh6.googleusercontent.com/-74Z5qj4bTDE/URqu6LSrJrI/AAAAAAAAAbs/XzmVkw90szQ/s1024/Orchid.jpg",
- "https://lh6.googleusercontent.com/-lEQE4h6TePE/URqu6t_lSkI/AAAAAAAAAbs/zvGYKOea_qY/s1024/Over%252520there.jpg",
- "https://lh5.googleusercontent.com/-cauH-53JH2M/URqu66v_USI/AAAAAAAAAbs/EucwwqclfKQ/s1024/Plumes.jpg",
- "https://lh3.googleusercontent.com/-eDLT2jHDoy4/URqu7axzkAI/AAAAAAAAAbs/iVZE-xJ7lZs/s1024/Rainbokeh.jpg",
- "https://lh5.googleusercontent.com/-j1NLqEFIyco/URqu8L1CGcI/AAAAAAAAAbs/aqZkgX66zlI/s1024/Rainbow.jpg",
- "https://lh5.googleusercontent.com/-DRnqmK0t4VU/URqu8XYN9yI/AAAAAAAAAbs/LgvF_592WLU/s1024/Rice%252520Fields.jpg",
- "https://lh3.googleusercontent.com/-hwh1v3EOGcQ/URqu8qOaKwI/AAAAAAAAAbs/IljRJRnbJGw/s1024/Rockaway%252520Fire%252520Sky.jpg",
- "https://lh5.googleusercontent.com/-wjV6FQk7tlk/URqu9jCQ8sI/AAAAAAAAAbs/RyYUpdo-c9o/s1024/Rockaway%252520Flow.jpg",
- "https://lh6.googleusercontent.com/-6cAXNfo7D20/URqu-BdzgPI/AAAAAAAAAbs/OmsYllzJqwo/s1024/Rockaway%252520Sunset%252520Sky.jpg",
- "https://lh3.googleusercontent.com/-sl8fpGPS-RE/URqu_BOkfgI/AAAAAAAAAbs/Dg2Fv-JxOeg/s1024/Russian%252520Ridge%252520Sunset.jpg",
- "https://lh6.googleusercontent.com/-gVtY36mMBIg/URqu_q91lkI/AAAAAAAAAbs/3CiFMBcy5MA/s1024/Rust%252520Knot.jpg",
- "https://lh6.googleusercontent.com/-GHeImuHqJBE/URqu_FKfVLI/AAAAAAAAAbs/axuEJeqam7Q/s1024/Sailing%252520Stones.jpg",
- "https://lh3.googleusercontent.com/-hBbYZjTOwGc/URqu_ycpIrI/AAAAAAAAAbs/nAdJUXnGJYE/s1024/Seahorse.jpg",
- "https://lh3.googleusercontent.com/-Iwi6-i6IexY/URqvAYZHsVI/AAAAAAAAAbs/5ETWl4qXsFE/s1024/Shinjuku%252520Street.jpg",
- "https://lh6.googleusercontent.com/-amhnySTM_MY/URqvAlb5KoI/AAAAAAAAAbs/pFCFgzlKsn0/s1024/Sierra%252520Heavens.jpg",
- "https://lh5.googleusercontent.com/-dJgjepFrYSo/URqvBVJZrAI/AAAAAAAAAbs/v-F5QWpYO6s/s1024/Sierra%252520Sunset.jpg",
- "https://lh4.googleusercontent.com/-Z4zGiC5nWdc/URqvBdEwivI/AAAAAAAAAbs/ZRZR1VJ84QA/s1024/Sin%252520Lights.jpg",
- "https://lh4.googleusercontent.com/-_0cYiWW8ccY/URqvBz3iM4I/AAAAAAAAAbs/9N_Wq8MhLTY/s1024/Starry%252520Lake.jpg",
- "https://lh3.googleusercontent.com/-A9LMoRyuQUA/URqvCYx_JoI/AAAAAAAAAbs/s7sde1Bz9cI/s1024/Starry%252520Night.jpg",
- "https://lh3.googleusercontent.com/-KtLJ3k858eY/URqvC_2h_bI/AAAAAAAAAbs/zzEBImwDA_g/s1024/Stream.jpg",
- "https://lh5.googleusercontent.com/-dFB7Lad6RcA/URqvDUftwWI/AAAAAAAAAbs/BrhoUtXTN7o/s1024/Strip%252520Sunset.jpg",
- "https://lh5.googleusercontent.com/-at6apgFiN20/URqvDyffUZI/AAAAAAAAAbs/clABCx171bE/s1024/Sunset%252520Hills.jpg",
- "https://lh4.googleusercontent.com/-7-EHhtQthII/URqvEYTk4vI/AAAAAAAAAbs/QSJZoB3YjVg/s1024/Tenaya%252520Lake%2525202.jpg",
- "https://lh6.googleusercontent.com/-8MrjV_a-Pok/URqvFC5repI/AAAAAAAAAbs/9inKTg9fbCE/s1024/Tenaya%252520Lake.jpg",
- "https://lh5.googleusercontent.com/-B1HW-z4zwao/URqvFWYRwUI/AAAAAAAAAbs/8Peli53Bs8I/s1024/The%252520Cave%252520BW.jpg",
- "https://lh3.googleusercontent.com/-PO4E-xZKAnQ/URqvGRqjYkI/AAAAAAAAAbs/42nyADFsXag/s1024/The%252520Fisherman.jpg",
- "https://lh4.googleusercontent.com/-iLyZlzfdy7s/URqvG0YScdI/AAAAAAAAAbs/1J9eDKmkXtk/s1024/The%252520Night%252520is%252520Coming.jpg",
- "https://lh6.googleusercontent.com/-G-k7YkkUco0/URqvHhah6fI/AAAAAAAAAbs/_taQQG7t0vo/s1024/The%252520Road.jpg",
- "https://lh6.googleusercontent.com/-h-ALJt7kSus/URqvIThqYfI/AAAAAAAAAbs/ejiv35olWS8/s1024/Tokyo%252520Heights.jpg",
- "https://lh5.googleusercontent.com/-Hy9k-TbS7xg/URqvIjQMOxI/AAAAAAAAAbs/RSpmmOATSkg/s1024/Tokyo%252520Highway.jpg",
- "https://lh6.googleusercontent.com/-83oOvMb4OZs/URqvJL0T7lI/AAAAAAAAAbs/c5TECZ6RONM/s1024/Tokyo%252520Smog.jpg",
- "https://lh3.googleusercontent.com/-FB-jfgREEfI/URqvJI3EXAI/AAAAAAAAAbs/XfyweiRF4v8/s1024/Tufa%252520at%252520Night.jpg",
- "https://lh4.googleusercontent.com/-vngKD5Z1U8w/URqvJUCEgPI/AAAAAAAAAbs/ulxCMVcU6EU/s1024/Valley%252520Sunset.jpg",
- "https://lh6.googleusercontent.com/-DOz5I2E2oMQ/URqvKMND1kI/AAAAAAAAAbs/Iqf0IsInleo/s1024/Windmill%252520Sunrise.jpg",
- "https://lh5.googleusercontent.com/-biyiyWcJ9MU/URqvKculiAI/AAAAAAAAAbs/jyPsCplJOpE/s1024/Windmill.jpg",
- "https://lh4.googleusercontent.com/-PDT167_xRdA/URqvK36mLcI/AAAAAAAAAbs/oi2ik9QseMI/s1024/Windmills.jpg",
- "https://lh5.googleusercontent.com/-kI_QdYx7VlU/URqvLXCB6gI/AAAAAAAAAbs/N31vlZ6u89o/s1024/Yet%252520Another%252520Rockaway%252520Sunset.jpg",
- "https://lh4.googleusercontent.com/-e9NHZ5k5MSs/URqvMIBZjtI/AAAAAAAAAbs/1fV810rDNfQ/s1024/Yosemite%252520Tree.jpg",
- };
-
- /**
- * This are PicasaWeb thumbnail URLs and could potentially change. Ideally the PicasaWeb API
- * should be used to fetch the URLs.
- *
- * Credit to Romain Guy for the photos:
- * http://www.curious-creature.org/
- * https://plus.google.com/109538161516040592207/about
- * http://www.flickr.com/photos/romainguy
- */
- public final static String[] imageThumbUrls = new String[] {
- "https://lh6.googleusercontent.com/-55osAWw3x0Q/URquUtcFr5I/AAAAAAAAAbs/rWlj1RUKrYI/s240-c/A%252520Photographer.jpg",
- "https://lh4.googleusercontent.com/--dq8niRp7W4/URquVgmXvgI/AAAAAAAAAbs/-gnuLQfNnBA/s240-c/A%252520Song%252520of%252520Ice%252520and%252520Fire.jpg",
- "https://lh5.googleusercontent.com/-7qZeDtRKFKc/URquWZT1gOI/AAAAAAAAAbs/hqWgteyNXsg/s240-c/Another%252520Rockaway%252520Sunset.jpg",
- "https://lh3.googleusercontent.com/--L0Km39l5J8/URquXHGcdNI/AAAAAAAAAbs/3ZrSJNrSomQ/s240-c/Antelope%252520Butte.jpg",
- "https://lh6.googleusercontent.com/-8HO-4vIFnlw/URquZnsFgtI/AAAAAAAAAbs/WT8jViTF7vw/s240-c/Antelope%252520Hallway.jpg",
- "https://lh4.googleusercontent.com/-WIuWgVcU3Qw/URqubRVcj4I/AAAAAAAAAbs/YvbwgGjwdIQ/s240-c/Antelope%252520Walls.jpg",
- "https://lh6.googleusercontent.com/-UBmLbPELvoQ/URqucCdv0kI/AAAAAAAAAbs/IdNhr2VQoQs/s240-c/Apre%2525CC%252580s%252520la%252520Pluie.jpg",
- "https://lh3.googleusercontent.com/-s-AFpvgSeew/URquc6dF-JI/AAAAAAAAAbs/Mt3xNGRUd68/s240-c/Backlit%252520Cloud.jpg",
- "https://lh5.googleusercontent.com/-bvmif9a9YOQ/URquea3heHI/AAAAAAAAAbs/rcr6wyeQtAo/s240-c/Bee%252520and%252520Flower.jpg",
- "https://lh5.googleusercontent.com/-n7mdm7I7FGs/URqueT_BT-I/AAAAAAAAAbs/9MYmXlmpSAo/s240-c/Bonzai%252520Rock%252520Sunset.jpg",
- "https://lh6.googleusercontent.com/-4CN4X4t0M1k/URqufPozWzI/AAAAAAAAAbs/8wK41lg1KPs/s240-c/Caterpillar.jpg",
- "https://lh3.googleusercontent.com/-rrFnVC8xQEg/URqufdrLBaI/AAAAAAAAAbs/s69WYy_fl1E/s240-c/Chess.jpg",
- "https://lh5.googleusercontent.com/-WVpRptWH8Yw/URqugh-QmDI/AAAAAAAAAbs/E-MgBgtlUWU/s240-c/Chihuly.jpg",
- "https://lh5.googleusercontent.com/-0BDXkYmckbo/URquhKFW84I/AAAAAAAAAbs/ogQtHCTk2JQ/s240-c/Closed%252520Door.jpg",
- "https://lh3.googleusercontent.com/-PyggXXZRykM/URquh-kVvoI/AAAAAAAAAbs/hFtDwhtrHHQ/s240-c/Colorado%252520River%252520Sunset.jpg",
- "https://lh3.googleusercontent.com/-ZAs4dNZtALc/URquikvOCWI/AAAAAAAAAbs/DXz4h3dll1Y/s240-c/Colors%252520of%252520Autumn.jpg",
- "https://lh4.googleusercontent.com/-GztnWEIiMz8/URqukVCU7bI/AAAAAAAAAbs/jo2Hjv6MZ6M/s240-c/Countryside.jpg",
- "https://lh4.googleusercontent.com/-bEg9EZ9QoiM/URquklz3FGI/AAAAAAAAAbs/UUuv8Ac2BaE/s240-c/Death%252520Valley%252520-%252520Dunes.jpg",
- "https://lh6.googleusercontent.com/-ijQJ8W68tEE/URqulGkvFEI/AAAAAAAAAbs/zPXvIwi_rFw/s240-c/Delicate%252520Arch.jpg",
- "https://lh5.googleusercontent.com/-Oh8mMy2ieng/URqullDwehI/AAAAAAAAAbs/TbdeEfsaIZY/s240-c/Despair.jpg",
- "https://lh5.googleusercontent.com/-gl0y4UiAOlk/URqumC_KjBI/AAAAAAAAAbs/PM1eT7dn4oo/s240-c/Eagle%252520Fall%252520Sunrise.jpg",
- "https://lh3.googleusercontent.com/-hYYHd2_vXPQ/URqumtJa9eI/AAAAAAAAAbs/wAalXVkbSh0/s240-c/Electric%252520Storm.jpg",
- "https://lh5.googleusercontent.com/-PyY_yiyjPTo/URqunUOhHFI/AAAAAAAAAbs/azZoULNuJXc/s240-c/False%252520Kiva.jpg",
- "https://lh6.googleusercontent.com/-PYvLVdvXywk/URqunwd8hfI/AAAAAAAAAbs/qiMwgkFvf6I/s240-c/Fitzgerald%252520Streaks.jpg",
- "https://lh4.googleusercontent.com/-KIR_UobIIqY/URquoCZ9SlI/AAAAAAAAAbs/Y4d4q8sXu4c/s240-c/Foggy%252520Sunset.jpg",
- "https://lh6.googleusercontent.com/-9lzOk_OWZH0/URquoo4xYoI/AAAAAAAAAbs/AwgzHtNVCwU/s240-c/Frantic.jpg",
- "https://lh3.googleusercontent.com/-0X3JNaKaz48/URqupH78wpI/AAAAAAAAAbs/lHXxu_zbH8s/s240-c/Golden%252520Gate%252520Afternoon.jpg",
- "https://lh6.googleusercontent.com/-95sb5ag7ABc/URqupl95RDI/AAAAAAAAAbs/g73R20iVTRA/s240-c/Golden%252520Gate%252520Fog.jpg",
- "https://lh3.googleusercontent.com/-JB9v6rtgHhk/URqup21F-zI/AAAAAAAAAbs/64Fb8qMZWXk/s240-c/Golden%252520Grass.jpg",
- "https://lh4.googleusercontent.com/-EIBGfnuLtII/URquqVHwaRI/AAAAAAAAAbs/FA4McV2u8VE/s240-c/Grand%252520Teton.jpg",
- "https://lh4.googleusercontent.com/-WoMxZvmN9nY/URquq1v2AoI/AAAAAAAAAbs/grj5uMhL6NA/s240-c/Grass%252520Closeup.jpg",
- "https://lh3.googleusercontent.com/-6hZiEHXx64Q/URqurxvNdqI/AAAAAAAAAbs/kWMXM3o5OVI/s240-c/Green%252520Grass.jpg",
- "https://lh5.googleusercontent.com/-6LVb9OXtQ60/URquteBFuKI/AAAAAAAAAbs/4F4kRgecwFs/s240-c/Hanging%252520Leaf.jpg",
- "https://lh4.googleusercontent.com/-zAvf__52ONk/URqutT_IuxI/AAAAAAAAAbs/D_bcuc0thoU/s240-c/Highway%2525201.jpg",
- "https://lh6.googleusercontent.com/-H4SrUg615rA/URquuL27fXI/AAAAAAAAAbs/4aEqJfiMsOU/s240-c/Horseshoe%252520Bend%252520Sunset.jpg",
- "https://lh4.googleusercontent.com/-JhFi4fb_Pqw/URquuX-QXbI/AAAAAAAAAbs/IXpYUxuweYM/s240-c/Horseshoe%252520Bend.jpg",
- "https://lh5.googleusercontent.com/-UGgssvFRJ7g/URquueyJzGI/AAAAAAAAAbs/yYIBlLT0toM/s240-c/Into%252520the%252520Blue.jpg",
- "https://lh3.googleusercontent.com/-CH7KoupI7uI/URquu0FF__I/AAAAAAAAAbs/R7GDmI7v_G0/s240-c/Jelly%252520Fish%2525202.jpg",
- "https://lh4.googleusercontent.com/-pwuuw6yhg8U/URquvPxR3FI/AAAAAAAAAbs/VNGk6f-tsGE/s240-c/Jelly%252520Fish%2525203.jpg",
- "https://lh5.googleusercontent.com/-GoUQVw1fnFw/URquv6xbC0I/AAAAAAAAAbs/zEUVTQQ43Zc/s240-c/Kauai.jpg",
- "https://lh6.googleusercontent.com/-8QdYYQEpYjw/URquwvdh88I/AAAAAAAAAbs/cktDy-ysfHo/s240-c/Kyoto%252520Sunset.jpg",
- "https://lh4.googleusercontent.com/-vPeekyDjOE0/URquwzJ28qI/AAAAAAAAAbs/qxcyXULsZrg/s240-c/Lake%252520Tahoe%252520Colors.jpg",
- "https://lh4.googleusercontent.com/-xBPxWpD4yxU/URquxWHk8AI/AAAAAAAAAbs/ARDPeDYPiMY/s240-c/Lava%252520from%252520the%252520Sky.jpg",
- "https://lh3.googleusercontent.com/-897VXrJB6RE/URquxxxd-5I/AAAAAAAAAbs/j-Cz4T4YvIw/s240-c/Leica%25252050mm%252520Summilux.jpg",
- "https://lh5.googleusercontent.com/-qSJ4D4iXzGo/URquyDWiJ1I/AAAAAAAAAbs/k2pBXeWehOA/s240-c/Leica%25252050mm%252520Summilux.jpg",
- "https://lh6.googleusercontent.com/-dwlPg83vzLg/URquylTVuFI/AAAAAAAAAbs/G6SyQ8b4YsI/s240-c/Leica%252520M8%252520%252528Front%252529.jpg",
- "https://lh3.googleusercontent.com/-R3_EYAyJvfk/URquzQBv8eI/AAAAAAAAAbs/b9xhpUM3pEI/s240-c/Light%252520to%252520Sand.jpg",
- "https://lh3.googleusercontent.com/-fHY5h67QPi0/URqu0Cp4J1I/AAAAAAAAAbs/0lG6m94Z6vM/s240-c/Little%252520Bit%252520of%252520Paradise.jpg",
- "https://lh5.googleusercontent.com/-TzF_LwrCnRM/URqu0RddPOI/AAAAAAAAAbs/gaj2dLiuX0s/s240-c/Lone%252520Pine%252520Sunset.jpg",
- "https://lh3.googleusercontent.com/-4HdpJ4_DXU4/URqu046dJ9I/AAAAAAAAAbs/eBOodtk2_uk/s240-c/Lonely%252520Rock.jpg",
- "https://lh6.googleusercontent.com/-erbF--z-W4s/URqu1ajSLkI/AAAAAAAAAbs/xjDCDO1INzM/s240-c/Longue%252520Vue.jpg",
- "https://lh6.googleusercontent.com/-0CXJRdJaqvc/URqu1opNZNI/AAAAAAAAAbs/PFB2oPUU7Lk/s240-c/Look%252520Me%252520in%252520the%252520Eye.jpg",
- "https://lh3.googleusercontent.com/-D_5lNxnDN6g/URqu2Tk7HVI/AAAAAAAAAbs/p0ddca9W__Y/s240-c/Lost%252520in%252520a%252520Field.jpg",
- "https://lh6.googleusercontent.com/-flsqwMrIk2Q/URqu24PcmjI/AAAAAAAAAbs/5ocIH85XofM/s240-c/Marshall%252520Beach%252520Sunset.jpg",
- "https://lh4.googleusercontent.com/-Y4lgryEVTmU/URqu28kG3gI/AAAAAAAAAbs/OjXpekqtbJ4/s240-c/Mono%252520Lake%252520Blue.jpg",
- "https://lh4.googleusercontent.com/-AaHAJPmcGYA/URqu3PIldHI/AAAAAAAAAbs/lcTqk1SIcRs/s240-c/Monument%252520Valley%252520Overlook.jpg",
- "https://lh4.googleusercontent.com/-vKxfdQ83dQA/URqu31Yq_BI/AAAAAAAAAbs/OUoGk_2AyfM/s240-c/Moving%252520Rock.jpg",
- "https://lh5.googleusercontent.com/-CG62QiPpWXg/URqu4ia4vRI/AAAAAAAAAbs/0YOdqLAlcAc/s240-c/Napali%252520Coast.jpg",
- "https://lh6.googleusercontent.com/-wdGrP5PMmJQ/URqu5PZvn7I/AAAAAAAAAbs/m0abEcdPXe4/s240-c/One%252520Wheel.jpg",
- "https://lh6.googleusercontent.com/-6WS5DoCGuOA/URqu5qx1UgI/AAAAAAAAAbs/giMw2ixPvrY/s240-c/Open%252520Sky.jpg",
- "https://lh6.googleusercontent.com/-u8EHKj8G8GQ/URqu55sM6yI/AAAAAAAAAbs/lIXX_GlTdmI/s240-c/Orange%252520Sunset.jpg",
- "https://lh6.googleusercontent.com/-74Z5qj4bTDE/URqu6LSrJrI/AAAAAAAAAbs/XzmVkw90szQ/s240-c/Orchid.jpg",
- "https://lh6.googleusercontent.com/-lEQE4h6TePE/URqu6t_lSkI/AAAAAAAAAbs/zvGYKOea_qY/s240-c/Over%252520there.jpg",
- "https://lh5.googleusercontent.com/-cauH-53JH2M/URqu66v_USI/AAAAAAAAAbs/EucwwqclfKQ/s240-c/Plumes.jpg",
- "https://lh3.googleusercontent.com/-eDLT2jHDoy4/URqu7axzkAI/AAAAAAAAAbs/iVZE-xJ7lZs/s240-c/Rainbokeh.jpg",
- "https://lh5.googleusercontent.com/-j1NLqEFIyco/URqu8L1CGcI/AAAAAAAAAbs/aqZkgX66zlI/s240-c/Rainbow.jpg",
- "https://lh5.googleusercontent.com/-DRnqmK0t4VU/URqu8XYN9yI/AAAAAAAAAbs/LgvF_592WLU/s240-c/Rice%252520Fields.jpg",
- "https://lh3.googleusercontent.com/-hwh1v3EOGcQ/URqu8qOaKwI/AAAAAAAAAbs/IljRJRnbJGw/s240-c/Rockaway%252520Fire%252520Sky.jpg",
- "https://lh5.googleusercontent.com/-wjV6FQk7tlk/URqu9jCQ8sI/AAAAAAAAAbs/RyYUpdo-c9o/s240-c/Rockaway%252520Flow.jpg",
- "https://lh6.googleusercontent.com/-6cAXNfo7D20/URqu-BdzgPI/AAAAAAAAAbs/OmsYllzJqwo/s240-c/Rockaway%252520Sunset%252520Sky.jpg",
- "https://lh3.googleusercontent.com/-sl8fpGPS-RE/URqu_BOkfgI/AAAAAAAAAbs/Dg2Fv-JxOeg/s240-c/Russian%252520Ridge%252520Sunset.jpg",
- "https://lh6.googleusercontent.com/-gVtY36mMBIg/URqu_q91lkI/AAAAAAAAAbs/3CiFMBcy5MA/s240-c/Rust%252520Knot.jpg",
- "https://lh6.googleusercontent.com/-GHeImuHqJBE/URqu_FKfVLI/AAAAAAAAAbs/axuEJeqam7Q/s240-c/Sailing%252520Stones.jpg",
- "https://lh3.googleusercontent.com/-hBbYZjTOwGc/URqu_ycpIrI/AAAAAAAAAbs/nAdJUXnGJYE/s240-c/Seahorse.jpg",
- "https://lh3.googleusercontent.com/-Iwi6-i6IexY/URqvAYZHsVI/AAAAAAAAAbs/5ETWl4qXsFE/s240-c/Shinjuku%252520Street.jpg",
- "https://lh6.googleusercontent.com/-amhnySTM_MY/URqvAlb5KoI/AAAAAAAAAbs/pFCFgzlKsn0/s240-c/Sierra%252520Heavens.jpg",
- "https://lh5.googleusercontent.com/-dJgjepFrYSo/URqvBVJZrAI/AAAAAAAAAbs/v-F5QWpYO6s/s240-c/Sierra%252520Sunset.jpg",
- "https://lh4.googleusercontent.com/-Z4zGiC5nWdc/URqvBdEwivI/AAAAAAAAAbs/ZRZR1VJ84QA/s240-c/Sin%252520Lights.jpg",
- "https://lh4.googleusercontent.com/-_0cYiWW8ccY/URqvBz3iM4I/AAAAAAAAAbs/9N_Wq8MhLTY/s240-c/Starry%252520Lake.jpg",
- "https://lh3.googleusercontent.com/-A9LMoRyuQUA/URqvCYx_JoI/AAAAAAAAAbs/s7sde1Bz9cI/s240-c/Starry%252520Night.jpg",
- "https://lh3.googleusercontent.com/-KtLJ3k858eY/URqvC_2h_bI/AAAAAAAAAbs/zzEBImwDA_g/s240-c/Stream.jpg",
- "https://lh5.googleusercontent.com/-dFB7Lad6RcA/URqvDUftwWI/AAAAAAAAAbs/BrhoUtXTN7o/s240-c/Strip%252520Sunset.jpg",
- "https://lh5.googleusercontent.com/-at6apgFiN20/URqvDyffUZI/AAAAAAAAAbs/clABCx171bE/s240-c/Sunset%252520Hills.jpg",
- "https://lh4.googleusercontent.com/-7-EHhtQthII/URqvEYTk4vI/AAAAAAAAAbs/QSJZoB3YjVg/s240-c/Tenaya%252520Lake%2525202.jpg",
- "https://lh6.googleusercontent.com/-8MrjV_a-Pok/URqvFC5repI/AAAAAAAAAbs/9inKTg9fbCE/s240-c/Tenaya%252520Lake.jpg",
- "https://lh5.googleusercontent.com/-B1HW-z4zwao/URqvFWYRwUI/AAAAAAAAAbs/8Peli53Bs8I/s240-c/The%252520Cave%252520BW.jpg",
- "https://lh3.googleusercontent.com/-PO4E-xZKAnQ/URqvGRqjYkI/AAAAAAAAAbs/42nyADFsXag/s240-c/The%252520Fisherman.jpg",
- "https://lh4.googleusercontent.com/-iLyZlzfdy7s/URqvG0YScdI/AAAAAAAAAbs/1J9eDKmkXtk/s240-c/The%252520Night%252520is%252520Coming.jpg",
- "https://lh6.googleusercontent.com/-G-k7YkkUco0/URqvHhah6fI/AAAAAAAAAbs/_taQQG7t0vo/s240-c/The%252520Road.jpg",
- "https://lh6.googleusercontent.com/-h-ALJt7kSus/URqvIThqYfI/AAAAAAAAAbs/ejiv35olWS8/s240-c/Tokyo%252520Heights.jpg",
- "https://lh5.googleusercontent.com/-Hy9k-TbS7xg/URqvIjQMOxI/AAAAAAAAAbs/RSpmmOATSkg/s240-c/Tokyo%252520Highway.jpg",
- "https://lh6.googleusercontent.com/-83oOvMb4OZs/URqvJL0T7lI/AAAAAAAAAbs/c5TECZ6RONM/s240-c/Tokyo%252520Smog.jpg",
- "https://lh3.googleusercontent.com/-FB-jfgREEfI/URqvJI3EXAI/AAAAAAAAAbs/XfyweiRF4v8/s240-c/Tufa%252520at%252520Night.jpg",
- "https://lh4.googleusercontent.com/-vngKD5Z1U8w/URqvJUCEgPI/AAAAAAAAAbs/ulxCMVcU6EU/s240-c/Valley%252520Sunset.jpg",
- "https://lh6.googleusercontent.com/-DOz5I2E2oMQ/URqvKMND1kI/AAAAAAAAAbs/Iqf0IsInleo/s240-c/Windmill%252520Sunrise.jpg",
- "https://lh5.googleusercontent.com/-biyiyWcJ9MU/URqvKculiAI/AAAAAAAAAbs/jyPsCplJOpE/s240-c/Windmill.jpg",
- "https://lh4.googleusercontent.com/-PDT167_xRdA/URqvK36mLcI/AAAAAAAAAbs/oi2ik9QseMI/s240-c/Windmills.jpg",
- "https://lh5.googleusercontent.com/-kI_QdYx7VlU/URqvLXCB6gI/AAAAAAAAAbs/N31vlZ6u89o/s240-c/Yet%252520Another%252520Rockaway%252520Sunset.jpg",
- "https://lh4.googleusercontent.com/-e9NHZ5k5MSs/URqvMIBZjtI/AAAAAAAAAbs/1fV810rDNfQ/s240-c/Yosemite%252520Tree.jpg",
- };
-}
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageDetailActivity.java b/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageDetailActivity.java
deleted file mode 100644
index 05d7b03f0..000000000
--- a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageDetailActivity.java
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * 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.bitmapfun.ui;
-
-import android.annotation.TargetApi;
-import android.app.ActionBar;
-import android.os.Build.VERSION_CODES;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentActivity;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentStatePagerAdapter;
-import android.support.v4.app.NavUtils;
-import android.support.v4.view.ViewPager;
-import android.util.DisplayMetrics;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.WindowManager.LayoutParams;
-import android.widget.Toast;
-
-import com.example.android.bitmapfun.BuildConfig;
-import com.example.android.bitmapfun.R;
-import com.example.android.bitmapfun.provider.Images;
-import com.example.android.bitmapfun.util.ImageCache;
-import com.example.android.bitmapfun.util.ImageFetcher;
-import com.example.android.bitmapfun.util.Utils;
-
-public class ImageDetailActivity extends FragmentActivity implements OnClickListener {
- private static final String IMAGE_CACHE_DIR = "images";
- public static final String EXTRA_IMAGE = "extra_image";
-
- private ImagePagerAdapter mAdapter;
- private ImageFetcher mImageFetcher;
- private ViewPager mPager;
-
- @TargetApi(VERSION_CODES.HONEYCOMB)
- @Override
- public void onCreate(Bundle savedInstanceState) {
- if (BuildConfig.DEBUG) {
- Utils.enableStrictMode();
- }
- super.onCreate(savedInstanceState);
- setContentView(R.layout.image_detail_pager);
-
- // Fetch screen height and width, to use as our max size when loading images as this
- // activity runs full screen
- final DisplayMetrics displayMetrics = new DisplayMetrics();
- getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
- final int height = displayMetrics.heightPixels;
- final int width = displayMetrics.widthPixels;
-
- // For this sample we'll use half of the longest width to resize our images. As the
- // image scaling ensures the image is larger than this, we should be left with a
- // resolution that is appropriate for both portrait and landscape. For best image quality
- // we shouldn't divide by 2, but this will use more memory and require a larger memory
- // cache.
- final int longest = (height > width ? height : width) / 2;
-
- ImageCache.ImageCacheParams cacheParams =
- new ImageCache.ImageCacheParams(this, IMAGE_CACHE_DIR);
- cacheParams.setMemCacheSizePercent(0.25f); // Set memory cache to 25% of app memory
-
- // The ImageFetcher takes care of loading images into our ImageView children asynchronously
- mImageFetcher = new ImageFetcher(this, longest);
- mImageFetcher.addImageCache(getSupportFragmentManager(), cacheParams);
- mImageFetcher.setImageFadeIn(false);
-
- // Set up ViewPager and backing adapter
- mAdapter = new ImagePagerAdapter(getSupportFragmentManager(), Images.imageUrls.length);
- mPager = (ViewPager) findViewById(R.id.pager);
- mPager.setAdapter(mAdapter);
- mPager.setPageMargin((int) getResources().getDimension(R.dimen.image_detail_pager_margin));
- mPager.setOffscreenPageLimit(2);
-
- // Set up activity to go full screen
- getWindow().addFlags(LayoutParams.FLAG_FULLSCREEN);
-
- // Enable some additional newer visibility and ActionBar features to create a more
- // immersive photo viewing experience
- if (Utils.hasHoneycomb()) {
- final ActionBar actionBar = getActionBar();
-
- // Hide title text and set home as up
- actionBar.setDisplayShowTitleEnabled(false);
- actionBar.setDisplayHomeAsUpEnabled(true);
-
- // Hide and show the ActionBar as the visibility changes
- mPager.setOnSystemUiVisibilityChangeListener(
- new View.OnSystemUiVisibilityChangeListener() {
- @Override
- public void onSystemUiVisibilityChange(int vis) {
- if ((vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) {
- actionBar.hide();
- } else {
- actionBar.show();
- }
- }
- });
-
- // Start low profile mode and hide ActionBar
- mPager.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
- actionBar.hide();
- }
-
- // Set the current item based on the extra passed in to this activity
- final int extraCurrentItem = getIntent().getIntExtra(EXTRA_IMAGE, -1);
- if (extraCurrentItem != -1) {
- mPager.setCurrentItem(extraCurrentItem);
- }
- }
-
- @Override
- public void onResume() {
- super.onResume();
- mImageFetcher.setExitTasksEarly(false);
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- mImageFetcher.setExitTasksEarly(true);
- mImageFetcher.flushCache();
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- mImageFetcher.closeCache();
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- NavUtils.navigateUpFromSameTask(this);
- return true;
- case R.id.clear_cache:
- mImageFetcher.clearCache();
- Toast.makeText(
- this, R.string.clear_cache_complete_toast,Toast.LENGTH_SHORT).show();
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.main_menu, menu);
- return true;
- }
-
- /**
- * Called by the ViewPager child fragments to load images via the one ImageFetcher
- */
- public ImageFetcher getImageFetcher() {
- return mImageFetcher;
- }
-
- /**
- * The main adapter that backs the ViewPager. A subclass of FragmentStatePagerAdapter as there
- * could be a large number of items in the ViewPager and we don't want to retain them all in
- * memory at once but create/destroy them on the fly.
- */
- private class ImagePagerAdapter extends FragmentStatePagerAdapter {
- private final int mSize;
-
- public ImagePagerAdapter(FragmentManager fm, int size) {
- super(fm);
- mSize = size;
- }
-
- @Override
- public int getCount() {
- return mSize;
- }
-
- @Override
- public Fragment getItem(int position) {
- return ImageDetailFragment.newInstance(Images.imageUrls[position]);
- }
- }
-
- /**
- * Set on the ImageView in the ViewPager children fragments, to enable/disable low profile mode
- * when the ImageView is touched.
- */
- @TargetApi(VERSION_CODES.HONEYCOMB)
- @Override
- public void onClick(View v) {
- final int vis = mPager.getSystemUiVisibility();
- if ((vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) {
- mPager.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
- } else {
- mPager.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
- }
- }
-}
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageDetailFragment.java b/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageDetailFragment.java
deleted file mode 100644
index 9fff8a08a..000000000
--- a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageDetailFragment.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * 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.bitmapfun.ui;
-
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-
-import com.example.android.bitmapfun.R;
-import com.example.android.bitmapfun.util.ImageFetcher;
-import com.example.android.bitmapfun.util.ImageWorker;
-import com.example.android.bitmapfun.util.Utils;
-
-/**
- * This fragment will populate the children of the ViewPager from {@link ImageDetailActivity}.
- */
-public class ImageDetailFragment extends Fragment {
- private static final String IMAGE_DATA_EXTRA = "extra_image_data";
- private String mImageUrl;
- private ImageView mImageView;
- private ImageFetcher mImageFetcher;
-
- /**
- * Factory method to generate a new instance of the fragment given an image number.
- *
- * @param imageUrl The image url to load
- * @return A new instance of ImageDetailFragment with imageNum extras
- */
- public static ImageDetailFragment newInstance(String imageUrl) {
- final ImageDetailFragment f = new ImageDetailFragment();
-
- final Bundle args = new Bundle();
- args.putString(IMAGE_DATA_EXTRA, imageUrl);
- f.setArguments(args);
-
- return f;
- }
-
- /**
- * Empty constructor as per the Fragment documentation
- */
- public ImageDetailFragment() {}
-
- /**
- * Populate image using a url from extras, use the convenience factory method
- * {@link ImageDetailFragment#newInstance(String)} to create this fragment.
- */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- mImageUrl = getArguments() != null ? getArguments().getString(IMAGE_DATA_EXTRA) : null;
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- // Inflate and locate the main ImageView
- final View v = inflater.inflate(R.layout.image_detail_fragment, container, false);
- mImageView = (ImageView) v.findViewById(R.id.imageView);
- return v;
- }
-
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
-
- // Use the parent activity to load the image asynchronously into the ImageView (so a single
- // cache can be used over all pages in the ViewPager
- if (ImageDetailActivity.class.isInstance(getActivity())) {
- mImageFetcher = ((ImageDetailActivity) getActivity()).getImageFetcher();
- mImageFetcher.loadImage(mImageUrl, mImageView);
- }
-
- // Pass clicks on the ImageView to the parent activity to handle
- if (OnClickListener.class.isInstance(getActivity()) && Utils.hasHoneycomb()) {
- mImageView.setOnClickListener((OnClickListener) getActivity());
- }
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- if (mImageView != null) {
- // Cancel any pending image work
- ImageWorker.cancelWork(mImageView);
- mImageView.setImageDrawable(null);
- }
- }
-}
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageGridActivity.java b/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageGridActivity.java
deleted file mode 100644
index e7c7d1c43..000000000
--- a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageGridActivity.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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.bitmapfun.ui;
-
-import android.os.Bundle;
-import android.support.v4.app.FragmentActivity;
-import android.support.v4.app.FragmentTransaction;
-
-import com.example.android.bitmapfun.BuildConfig;
-import com.example.android.bitmapfun.util.Utils;
-
-/**
- * Simple FragmentActivity to hold the main {@link ImageGridFragment} and not much else.
- */
-public class ImageGridActivity extends FragmentActivity {
- private static final String TAG = "ImageGridActivity";
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- if (BuildConfig.DEBUG) {
- Utils.enableStrictMode();
- }
- super.onCreate(savedInstanceState);
-
- if (getSupportFragmentManager().findFragmentByTag(TAG) == null) {
- final FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
- ft.add(android.R.id.content, new ImageGridFragment(), TAG);
- ft.commit();
- }
- }
-}
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageGridFragment.java b/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageGridFragment.java
deleted file mode 100644
index ba4581aa1..000000000
--- a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageGridFragment.java
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- * 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.bitmapfun.ui;
-
-import android.annotation.TargetApi;
-import android.app.ActivityOptions;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Build.VERSION_CODES;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewGroup.LayoutParams;
-import android.view.ViewTreeObserver;
-import android.widget.AbsListView;
-import android.widget.AdapterView;
-import android.widget.BaseAdapter;
-import android.widget.GridView;
-import android.widget.ImageView;
-import android.widget.Toast;
-
-import com.example.android.bitmapfun.BuildConfig;
-import com.example.android.bitmapfun.R;
-import com.example.android.bitmapfun.provider.Images;
-import com.example.android.bitmapfun.util.ImageCache.ImageCacheParams;
-import com.example.android.bitmapfun.util.ImageFetcher;
-import com.example.android.bitmapfun.util.Utils;
-
-/**
- * The main fragment that powers the ImageGridActivity screen. Fairly straight forward GridView
- * implementation with the key addition being the ImageWorker class w/ImageCache to load children
- * asynchronously, keeping the UI nice and smooth and caching thumbnails for quick retrieval. The
- * cache is retained over configuration changes like orientation change so the images are populated
- * quickly if, for example, the user rotates the device.
- */
-public class ImageGridFragment extends Fragment implements AdapterView.OnItemClickListener {
- private static final String TAG = "ImageGridFragment";
- private static final String IMAGE_CACHE_DIR = "thumbs";
-
- private int mImageThumbSize;
- private int mImageThumbSpacing;
- private ImageAdapter mAdapter;
- private ImageFetcher mImageFetcher;
-
- /**
- * Empty constructor as per the Fragment documentation
- */
- public ImageGridFragment() {}
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setHasOptionsMenu(true);
-
- mImageThumbSize = getResources().getDimensionPixelSize(R.dimen.image_thumbnail_size);
- mImageThumbSpacing = getResources().getDimensionPixelSize(R.dimen.image_thumbnail_spacing);
-
- mAdapter = new ImageAdapter(getActivity());
-
- ImageCacheParams cacheParams = new ImageCacheParams(getActivity(), IMAGE_CACHE_DIR);
-
- cacheParams.setMemCacheSizePercent(0.25f); // Set memory cache to 25% of app memory
-
- // The ImageFetcher takes care of loading images into our ImageView children asynchronously
- mImageFetcher = new ImageFetcher(getActivity(), mImageThumbSize);
- mImageFetcher.setLoadingImage(R.drawable.empty_photo);
- mImageFetcher.addImageCache(getActivity().getSupportFragmentManager(), cacheParams);
- }
-
- @Override
- public View onCreateView(
- LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-
- final View v = inflater.inflate(R.layout.image_grid_fragment, container, false);
- final GridView mGridView = (GridView) v.findViewById(R.id.gridView);
- mGridView.setAdapter(mAdapter);
- mGridView.setOnItemClickListener(this);
- mGridView.setOnScrollListener(new AbsListView.OnScrollListener() {
- @Override
- public void onScrollStateChanged(AbsListView absListView, int scrollState) {
- // Pause fetcher to ensure smoother scrolling when flinging
- if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_FLING) {
- // Before Honeycomb pause image loading on scroll to help with performance
- if (!Utils.hasHoneycomb()) {
- mImageFetcher.setPauseWork(true);
- }
- } else {
- mImageFetcher.setPauseWork(false);
- }
- }
-
- @Override
- public void onScroll(AbsListView absListView, int firstVisibleItem,
- int visibleItemCount, int totalItemCount) {
- }
- });
-
- // This listener is used to get the final width of the GridView and then calculate the
- // number of columns and the width of each column. The width of each column is variable
- // as the GridView has stretchMode=columnWidth. The column width is used to set the height
- // of each view so we get nice square thumbnails.
- mGridView.getViewTreeObserver().addOnGlobalLayoutListener(
- new ViewTreeObserver.OnGlobalLayoutListener() {
- @Override
- public void onGlobalLayout() {
- if (mAdapter.getNumColumns() == 0) {
- final int numColumns = (int) Math.floor(
- mGridView.getWidth() / (mImageThumbSize + mImageThumbSpacing));
- if (numColumns > 0) {
- final int columnWidth =
- (mGridView.getWidth() / numColumns) - mImageThumbSpacing;
- mAdapter.setNumColumns(numColumns);
- mAdapter.setItemHeight(columnWidth);
- if (BuildConfig.DEBUG) {
- Log.d(TAG, "onCreateView - numColumns set to " + numColumns);
- }
- if (Utils.hasJellyBean()) {
- mGridView.getViewTreeObserver()
- .removeOnGlobalLayoutListener(this);
- } else {
- mGridView.getViewTreeObserver()
- .removeGlobalOnLayoutListener(this);
- }
- }
- }
- }
- });
-
- return v;
- }
-
- @Override
- public void onResume() {
- super.onResume();
- mImageFetcher.setExitTasksEarly(false);
- mAdapter.notifyDataSetChanged();
- }
-
- @Override
- public void onPause() {
- super.onPause();
- mImageFetcher.setPauseWork(false);
- mImageFetcher.setExitTasksEarly(true);
- mImageFetcher.flushCache();
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- mImageFetcher.closeCache();
- }
-
- @TargetApi(VERSION_CODES.JELLY_BEAN)
- @Override
- public void onItemClick(AdapterView> parent, View v, int position, long id) {
- final Intent i = new Intent(getActivity(), ImageDetailActivity.class);
- i.putExtra(ImageDetailActivity.EXTRA_IMAGE, (int) id);
- if (Utils.hasJellyBean()) {
- // makeThumbnailScaleUpAnimation() looks kind of ugly here as the loading spinner may
- // show plus the thumbnail image in GridView is cropped. so using
- // makeScaleUpAnimation() instead.
- ActivityOptions options =
- ActivityOptions.makeScaleUpAnimation(v, 0, 0, v.getWidth(), v.getHeight());
- getActivity().startActivity(i, options.toBundle());
- } else {
- startActivity(i);
- }
- }
-
- @Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- inflater.inflate(R.menu.main_menu, menu);
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.clear_cache:
- mImageFetcher.clearCache();
- Toast.makeText(getActivity(), R.string.clear_cache_complete_toast,
- Toast.LENGTH_SHORT).show();
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-
- /**
- * The main adapter that backs the GridView. This is fairly standard except the number of
- * columns in the GridView is used to create a fake top row of empty views as we use a
- * transparent ActionBar and don't want the real top row of images to start off covered by it.
- */
- private class ImageAdapter extends BaseAdapter {
-
- private final Context mContext;
- private int mItemHeight = 0;
- private int mNumColumns = 0;
- private int mActionBarHeight = 0;
- private GridView.LayoutParams mImageViewLayoutParams;
-
- public ImageAdapter(Context context) {
- super();
- mContext = context;
- mImageViewLayoutParams = new GridView.LayoutParams(
- LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
- // Calculate ActionBar height
- TypedValue tv = new TypedValue();
- if (context.getTheme().resolveAttribute(
- android.R.attr.actionBarSize, tv, true)) {
- mActionBarHeight = TypedValue.complexToDimensionPixelSize(
- tv.data, context.getResources().getDisplayMetrics());
- }
- }
-
- @Override
- public int getCount() {
- // If columns have yet to be determined, return no items
- if (getNumColumns() == 0) {
- return 0;
- }
-
- // Size + number of columns for top empty row
- return Images.imageThumbUrls.length + mNumColumns;
- }
-
- @Override
- public Object getItem(int position) {
- return position < mNumColumns ?
- null : Images.imageThumbUrls[position - mNumColumns];
- }
-
- @Override
- public long getItemId(int position) {
- return position < mNumColumns ? 0 : position - mNumColumns;
- }
-
- @Override
- public int getViewTypeCount() {
- // Two types of views, the normal ImageView and the top row of empty views
- return 2;
- }
-
- @Override
- public int getItemViewType(int position) {
- return (position < mNumColumns) ? 1 : 0;
- }
-
- @Override
- public boolean hasStableIds() {
- return true;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup container) {
- // First check if this is the top row
- if (position < mNumColumns) {
- if (convertView == null) {
- convertView = new View(mContext);
- }
- // Set empty view with height of ActionBar
- convertView.setLayoutParams(new AbsListView.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT, mActionBarHeight));
- return convertView;
- }
-
- // Now handle the main ImageView thumbnails
- ImageView imageView;
- if (convertView == null) { // if it's not recycled, instantiate and initialize
- imageView = new RecyclingImageView(mContext);
- imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
- imageView.setLayoutParams(mImageViewLayoutParams);
- } else { // Otherwise re-use the converted view
- imageView = (ImageView) convertView;
- }
-
- // Check the height matches our calculated column width
- if (imageView.getLayoutParams().height != mItemHeight) {
- imageView.setLayoutParams(mImageViewLayoutParams);
- }
-
- // Finally load the image asynchronously into the ImageView, this also takes care of
- // setting a placeholder image while the background thread runs
- mImageFetcher.loadImage(Images.imageThumbUrls[position - mNumColumns], imageView);
- return imageView;
- }
-
- /**
- * Sets the item height. Useful for when we know the column width so the height can be set
- * to match.
- *
- * @param height
- */
- public void setItemHeight(int height) {
- if (height == mItemHeight) {
- return;
- }
- mItemHeight = height;
- mImageViewLayoutParams =
- new GridView.LayoutParams(LayoutParams.MATCH_PARENT, mItemHeight);
- mImageFetcher.setImageSize(height);
- notifyDataSetChanged();
- }
-
- public void setNumColumns(int numColumns) {
- mNumColumns = numColumns;
- }
-
- public int getNumColumns() {
- return mNumColumns;
- }
- }
-}
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/RecyclingImageView.java b/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/RecyclingImageView.java
deleted file mode 100644
index 1bcc01465..000000000
--- a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/RecyclingImageView.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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.bitmapfun.ui;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
-import android.util.AttributeSet;
-import android.widget.ImageView;
-
-import com.example.android.bitmapfun.util.RecyclingBitmapDrawable;
-
-/**
- * Sub-class of ImageView which automatically notifies the drawable when it is
- * being displayed.
- */
-public class RecyclingImageView extends ImageView {
-
- public RecyclingImageView(Context context) {
- super(context);
- }
-
- public RecyclingImageView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- /**
- * @see android.widget.ImageView#onDetachedFromWindow()
- */
- @Override
- protected void onDetachedFromWindow() {
- // This has been detached from Window, so clear the drawable
- setImageDrawable(null);
-
- super.onDetachedFromWindow();
- }
-
- /**
- * @see android.widget.ImageView#setImageDrawable(android.graphics.drawable.Drawable)
- */
- @Override
- public void setImageDrawable(Drawable drawable) {
- // Keep hold of previous Drawable
- final Drawable previousDrawable = getDrawable();
-
- // Call super to set new Drawable
- super.setImageDrawable(drawable);
-
- // Notify new Drawable that it is being displayed
- notifyDrawable(drawable, true);
-
- // Notify old Drawable so it is no longer being displayed
- notifyDrawable(previousDrawable, false);
- }
-
- /**
- * Notifies the drawable that it's displayed state has changed.
- *
- * @param drawable
- * @param isDisplayed
- */
- private static void notifyDrawable(Drawable drawable, final boolean isDisplayed) {
- if (drawable instanceof RecyclingBitmapDrawable) {
- // The drawable is a CountingBitmapDrawable, so notify it
- ((RecyclingBitmapDrawable) drawable).setIsDisplayed(isDisplayed);
- } else if (drawable instanceof LayerDrawable) {
- // The drawable is a LayerDrawable, so recurse on each layer
- LayerDrawable layerDrawable = (LayerDrawable) drawable;
- for (int i = 0, z = layerDrawable.getNumberOfLayers(); i < z; i++) {
- notifyDrawable(layerDrawable.getDrawable(i), isDisplayed);
- }
- }
- }
-
-}
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/AsyncTask.java b/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/AsyncTask.java
deleted file mode 100644
index 018ce1a23..000000000
--- a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/AsyncTask.java
+++ /dev/null
@@ -1,693 +0,0 @@
-/*
- * Copyright (C) 2008 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.bitmapfun.util;
-
-import android.annotation.TargetApi;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Process;
-
-import java.util.ArrayDeque;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.Executor;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Executors;
-import java.util.concurrent.FutureTask;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * *************************************
- * Copied from JB release framework:
- * https://android.googlesource.com/platform/frameworks/base/+/jb-release/core/java/android/os/AsyncTask.java
- *
- * so that threading behavior on all OS versions is the same and we can tweak behavior by using
- * executeOnExecutor() if needed.
- *
- * There are 3 changes in this copy of AsyncTask:
- * -pre-HC a single thread executor is used for serial operation
- * (Executors.newSingleThreadExecutor) and is the default
- * -the default THREAD_POOL_EXECUTOR was changed to use DiscardOldestPolicy
- * -a new fixed thread pool called DUAL_THREAD_EXECUTOR was added
- * *************************************
- *
- *
AsyncTask enables proper and easy use of the UI thread. This class allows to
- * perform background operations and publish results on the UI thread without
- * having to manipulate threads and/or handlers.
- *
- *
AsyncTask is designed to be a helper class around {@link Thread} and {@link Handler}
- * and does not constitute a generic threading framework. AsyncTasks should ideally be
- * used for short operations (a few seconds at the most.) If you need to keep threads
- * running for long periods of time, it is highly recommended you use the various APIs
- * provided by the java.util.concurrent pacakge such as {@link Executor},
- * {@link ThreadPoolExecutor} and {@link FutureTask}.
- *
- *
An asynchronous task is defined by a computation that runs on a background thread and
- * whose result is published on the UI thread. An asynchronous task is defined by 3 generic
- * types, called Params, Progress and Result,
- * and 4 steps, called onPreExecute, doInBackground,
- * onProgressUpdate and onPostExecute.
- *
- *
- *
Developer Guides
- *
For more information about using tasks and threads, read the
- * Processes and
- * Threads developer guide.
- *
- *
- *
Usage
- *
AsyncTask must be subclassed to be used. The subclass will override at least
- * one method ({@link #doInBackground}), and most often will override a
- * second one ({@link #onPostExecute}.)
- *
- *
Here is an example of subclassing:
- *
- * private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
- * protected Long doInBackground(URL... urls) {
- * int count = urls.length;
- * long totalSize = 0;
- * for (int i = 0; i < count; i++) {
- * totalSize += Downloader.downloadFile(urls[i]);
- * publishProgress((int) ((i / (float) count) * 100));
- * // Escape early if cancel() is called
- * if (isCancelled()) break;
- * }
- * return totalSize;
- * }
- *
- * protected void onProgressUpdate(Integer... progress) {
- * setProgressPercent(progress[0]);
- * }
- *
- * protected void onPostExecute(Long result) {
- * showDialog("Downloaded " + result + " bytes");
- * }
- * }
- *
- *
- *
Once created, a task is executed very simply:
- *
- * new DownloadFilesTask().execute(url1, url2, url3);
- *
- *
- *
AsyncTask's generic types
- *
The three types used by an asynchronous task are the following:
- *
- *
Params, the type of the parameters sent to the task upon
- * execution.
- *
Progress, the type of the progress units published during
- * the background computation.
- *
Result, the type of the result of the background
- * computation.
- *
- *
Not all types are always used by an asynchronous task. To mark a type as unused,
- * simply use the type {@link Void}:
When an asynchronous task is executed, the task goes through 4 steps:
- *
- *
{@link #onPreExecute()}, invoked on the UI thread immediately after the task
- * is executed. This step is normally used to setup the task, for instance by
- * showing a progress bar in the user interface.
- *
{@link #doInBackground}, invoked on the background thread
- * immediately after {@link #onPreExecute()} finishes executing. This step is used
- * to perform background computation that can take a long time. The parameters
- * of the asynchronous task are passed to this step. The result of the computation must
- * be returned by this step and will be passed back to the last step. This step
- * can also use {@link #publishProgress} to publish one or more units
- * of progress. These values are published on the UI thread, in the
- * {@link #onProgressUpdate} step.
- *
{@link #onProgressUpdate}, invoked on the UI thread after a
- * call to {@link #publishProgress}. The timing of the execution is
- * undefined. This method is used to display any form of progress in the user
- * interface while the background computation is still executing. For instance,
- * it can be used to animate a progress bar or show logs in a text field.
- *
{@link #onPostExecute}, invoked on the UI thread after the background
- * computation finishes. The result of the background computation is passed to
- * this step as a parameter.
- *
- *
- *
Cancelling a task
- *
A task can be cancelled at any time by invoking {@link #cancel(boolean)}. Invoking
- * this method will cause subsequent calls to {@link #isCancelled()} to return true.
- * After invoking this method, {@link #onCancelled(Object)}, instead of
- * {@link #onPostExecute(Object)} will be invoked after {@link #doInBackground(Object[])}
- * returns. To ensure that a task is cancelled as quickly as possible, you should always
- * check the return value of {@link #isCancelled()} periodically from
- * {@link #doInBackground(Object[])}, if possible (inside a loop for instance.)
- *
- *
Threading rules
- *
There are a few threading rules that must be followed for this class to
- * work properly:
- *
- *
The AsyncTask class must be loaded on the UI thread. This is done
- * automatically as of {@link android.os.Build.VERSION_CODES#JELLY_BEAN}.
- *
The task instance must be created on the UI thread.
- *
{@link #execute} must be invoked on the UI thread.
- *
Do not call {@link #onPreExecute()}, {@link #onPostExecute},
- * {@link #doInBackground}, {@link #onProgressUpdate} manually.
- *
The task can be executed only once (an exception will be thrown if
- * a second execution is attempted.)
- *
- *
- *
Memory observability
- *
AsyncTask guarantees that all callback calls are synchronized in such a way that the following
- * operations are safe without explicit synchronizations.
- *
- *
Set member fields in the constructor or {@link #onPreExecute}, and refer to them
- * in {@link #doInBackground}.
- *
Set member fields in {@link #doInBackground}, and refer to them in
- * {@link #onProgressUpdate} and {@link #onPostExecute}.
- *
- *
- *
Order of execution
- *
When first introduced, AsyncTasks were executed serially on a single background
- * thread. Starting with {@link android.os.Build.VERSION_CODES#DONUT}, this was changed
- * to a pool of threads allowing multiple tasks to operate in parallel. Starting with
- * {@link android.os.Build.VERSION_CODES#HONEYCOMB}, tasks are executed on a single
- * thread to avoid common application errors caused by parallel execution.
- *
If you truly want parallel execution, you can invoke
- * {@link #executeOnExecutor(java.util.concurrent.Executor, Object[])} with
- * {@link #THREAD_POOL_EXECUTOR}.
- */
-public abstract class AsyncTask {
- private static final String LOG_TAG = "AsyncTask";
-
- private static final int CORE_POOL_SIZE = 5;
- private static final int MAXIMUM_POOL_SIZE = 128;
- private static final int KEEP_ALIVE = 1;
-
- private static final ThreadFactory sThreadFactory = new ThreadFactory() {
- private final AtomicInteger mCount = new AtomicInteger(1);
-
- public Thread newThread(Runnable r) {
- return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
- }
- };
-
- private static final BlockingQueue sPoolWorkQueue =
- new LinkedBlockingQueue(10);
-
- /**
- * An {@link Executor} that can be used to execute tasks in parallel.
- */
- public static final Executor THREAD_POOL_EXECUTOR
- = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
- TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory,
- new ThreadPoolExecutor.DiscardOldestPolicy());
-
- /**
- * An {@link Executor} that executes tasks one at a time in serial
- * order. This serialization is global to a particular process.
- */
- public static final Executor SERIAL_EXECUTOR = Utils.hasHoneycomb() ? new SerialExecutor() :
- Executors.newSingleThreadExecutor(sThreadFactory);
-
- public static final Executor DUAL_THREAD_EXECUTOR =
- Executors.newFixedThreadPool(2, sThreadFactory);
-
- private static final int MESSAGE_POST_RESULT = 0x1;
- private static final int MESSAGE_POST_PROGRESS = 0x2;
-
- private static final InternalHandler sHandler = new InternalHandler();
-
- private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
- private final WorkerRunnable mWorker;
- private final FutureTask mFuture;
-
- private volatile Status mStatus = Status.PENDING;
-
- private final AtomicBoolean mCancelled = new AtomicBoolean();
- private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
-
- @TargetApi(11)
- private static class SerialExecutor implements Executor {
- final ArrayDeque mTasks = new ArrayDeque();
- Runnable mActive;
-
- public synchronized void execute(final Runnable r) {
- mTasks.offer(new Runnable() {
- public void run() {
- try {
- r.run();
- } finally {
- scheduleNext();
- }
- }
- });
- if (mActive == null) {
- scheduleNext();
- }
- }
-
- protected synchronized void scheduleNext() {
- if ((mActive = mTasks.poll()) != null) {
- THREAD_POOL_EXECUTOR.execute(mActive);
- }
- }
- }
-
- /**
- * Indicates the current status of the task. Each status will be set only once
- * during the lifetime of a task.
- */
- public enum Status {
- /**
- * Indicates that the task has not been executed yet.
- */
- PENDING,
- /**
- * Indicates that the task is running.
- */
- RUNNING,
- /**
- * Indicates that {@link AsyncTask#onPostExecute} has finished.
- */
- FINISHED,
- }
-
- /** @hide Used to force static handler to be created. */
- public static void init() {
- sHandler.getLooper();
- }
-
- /** @hide */
- public static void setDefaultExecutor(Executor exec) {
- sDefaultExecutor = exec;
- }
-
- /**
- * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
- */
- public AsyncTask() {
- mWorker = new WorkerRunnable() {
- public Result call() throws Exception {
- mTaskInvoked.set(true);
-
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- //noinspection unchecked
- return postResult(doInBackground(mParams));
- }
- };
-
- mFuture = new FutureTask(mWorker) {
- @Override
- protected void done() {
- try {
- postResultIfNotInvoked(get());
- } catch (InterruptedException e) {
- android.util.Log.w(LOG_TAG, e);
- } catch (ExecutionException e) {
- throw new RuntimeException("An error occured while executing doInBackground()",
- e.getCause());
- } catch (CancellationException e) {
- postResultIfNotInvoked(null);
- }
- }
- };
- }
-
- private void postResultIfNotInvoked(Result result) {
- final boolean wasTaskInvoked = mTaskInvoked.get();
- if (!wasTaskInvoked) {
- postResult(result);
- }
- }
-
- private Result postResult(Result result) {
- @SuppressWarnings("unchecked")
- Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
- new AsyncTaskResult(this, result));
- message.sendToTarget();
- return result;
- }
-
- /**
- * Returns the current status of this task.
- *
- * @return The current status.
- */
- public final Status getStatus() {
- return mStatus;
- }
-
- /**
- * Override this method to perform a computation on a background thread. The
- * specified parameters are the parameters passed to {@link #execute}
- * by the caller of this task.
- *
- * This method can call {@link #publishProgress} to publish updates
- * on the UI thread.
- *
- * @param params The parameters of the task.
- *
- * @return A result, defined by the subclass of this task.
- *
- * @see #onPreExecute()
- * @see #onPostExecute
- * @see #publishProgress
- */
- protected abstract Result doInBackground(Params... params);
-
- /**
- * Runs on the UI thread before {@link #doInBackground}.
- *
- * @see #onPostExecute
- * @see #doInBackground
- */
- protected void onPreExecute() {
- }
-
- /**
- *
Runs on the UI thread after {@link #doInBackground}. The
- * specified result is the value returned by {@link #doInBackground}.
- *
- *
This method won't be invoked if the task was cancelled.
- *
- * @param result The result of the operation computed by {@link #doInBackground}.
- *
- * @see #onPreExecute
- * @see #doInBackground
- * @see #onCancelled(Object)
- */
- @SuppressWarnings({"UnusedDeclaration"})
- protected void onPostExecute(Result result) {
- }
-
- /**
- * Runs on the UI thread after {@link #publishProgress} is invoked.
- * The specified values are the values passed to {@link #publishProgress}.
- *
- * @param values The values indicating progress.
- *
- * @see #publishProgress
- * @see #doInBackground
- */
- @SuppressWarnings({"UnusedDeclaration"})
- protected void onProgressUpdate(Progress... values) {
- }
-
- /**
- *
Runs on the UI thread after {@link #cancel(boolean)} is invoked and
- * {@link #doInBackground(Object[])} has finished.
- *
- *
The default implementation simply invokes {@link #onCancelled()} and
- * ignores the result. If you write your own implementation, do not call
- * super.onCancelled(result).
- *
- * @param result The result, if any, computed in
- * {@link #doInBackground(Object[])}, can be null
- *
- * @see #cancel(boolean)
- * @see #isCancelled()
- */
- @SuppressWarnings({"UnusedParameters"})
- protected void onCancelled(Result result) {
- onCancelled();
- }
-
- /**
- *
Applications should preferably override {@link #onCancelled(Object)}.
- * This method is invoked by the default implementation of
- * {@link #onCancelled(Object)}.
- *
- *
Runs on the UI thread after {@link #cancel(boolean)} is invoked and
- * {@link #doInBackground(Object[])} has finished.
- *
- * @see #onCancelled(Object)
- * @see #cancel(boolean)
- * @see #isCancelled()
- */
- protected void onCancelled() {
- }
-
- /**
- * Returns true if this task was cancelled before it completed
- * normally. If you are calling {@link #cancel(boolean)} on the task,
- * the value returned by this method should be checked periodically from
- * {@link #doInBackground(Object[])} to end the task as soon as possible.
- *
- * @return true if task was cancelled before it completed
- *
- * @see #cancel(boolean)
- */
- public final boolean isCancelled() {
- return mCancelled.get();
- }
-
- /**
- *
Attempts to cancel execution of this task. This attempt will
- * fail if the task has already completed, already been cancelled,
- * or could not be cancelled for some other reason. If successful,
- * and this task has not started when cancel is called,
- * this task should never run. If the task has already started,
- * then the mayInterruptIfRunning parameter determines
- * whether the thread executing this task should be interrupted in
- * an attempt to stop the task.
- *
- *
Calling this method will result in {@link #onCancelled(Object)} being
- * invoked on the UI thread after {@link #doInBackground(Object[])}
- * returns. Calling this method guarantees that {@link #onPostExecute(Object)}
- * is never invoked. After invoking this method, you should check the
- * value returned by {@link #isCancelled()} periodically from
- * {@link #doInBackground(Object[])} to finish the task as early as
- * possible.
- *
- * @param mayInterruptIfRunning true if the thread executing this
- * task should be interrupted; otherwise, in-progress tasks are allowed
- * to complete.
- *
- * @return false if the task could not be cancelled,
- * typically because it has already completed normally;
- * true otherwise
- *
- * @see #isCancelled()
- * @see #onCancelled(Object)
- */
- public final boolean cancel(boolean mayInterruptIfRunning) {
- mCancelled.set(true);
- return mFuture.cancel(mayInterruptIfRunning);
- }
-
- /**
- * Waits if necessary for the computation to complete, and then
- * retrieves its result.
- *
- * @return The computed result.
- *
- * @throws CancellationException If the computation was cancelled.
- * @throws ExecutionException If the computation threw an exception.
- * @throws InterruptedException If the current thread was interrupted
- * while waiting.
- */
- public final Result get() throws InterruptedException, ExecutionException {
- return mFuture.get();
- }
-
- /**
- * Waits if necessary for at most the given time for the computation
- * to complete, and then retrieves its result.
- *
- * @param timeout Time to wait before cancelling the operation.
- * @param unit The time unit for the timeout.
- *
- * @return The computed result.
- *
- * @throws CancellationException If the computation was cancelled.
- * @throws ExecutionException If the computation threw an exception.
- * @throws InterruptedException If the current thread was interrupted
- * while waiting.
- * @throws TimeoutException If the wait timed out.
- */
- public final Result get(long timeout, TimeUnit unit) throws InterruptedException,
- ExecutionException, TimeoutException {
- return mFuture.get(timeout, unit);
- }
-
- /**
- * Executes the task with the specified parameters. The task returns
- * itself (this) so that the caller can keep a reference to it.
- *
- *
Note: this function schedules the task on a queue for a single background
- * thread or pool of threads depending on the platform version. When first
- * introduced, AsyncTasks were executed serially on a single background thread.
- * Starting with {@link android.os.Build.VERSION_CODES#DONUT}, this was changed
- * to a pool of threads allowing multiple tasks to operate in parallel. Starting
- * {@link android.os.Build.VERSION_CODES#HONEYCOMB}, tasks are back to being
- * executed on a single thread to avoid common application errors caused
- * by parallel execution. If you truly want parallel execution, you can use
- * the {@link #executeOnExecutor} version of this method
- * with {@link #THREAD_POOL_EXECUTOR}; however, see commentary there for warnings
- * on its use.
- *
- *
This method must be invoked on the UI thread.
- *
- * @param params The parameters of the task.
- *
- * @return This instance of AsyncTask.
- *
- * @throws IllegalStateException If {@link #getStatus()} returns either
- * {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
- *
- * @see #executeOnExecutor(java.util.concurrent.Executor, Object[])
- * @see #execute(Runnable)
- */
- public final AsyncTask execute(Params... params) {
- return executeOnExecutor(sDefaultExecutor, params);
- }
-
- /**
- * Executes the task with the specified parameters. The task returns
- * itself (this) so that the caller can keep a reference to it.
- *
- *
This method is typically used with {@link #THREAD_POOL_EXECUTOR} to
- * allow multiple tasks to run in parallel on a pool of threads managed by
- * AsyncTask, however you can also use your own {@link Executor} for custom
- * behavior.
- *
- *
Warning: Allowing multiple tasks to run in parallel from
- * a thread pool is generally not what one wants, because the order
- * of their operation is not defined. For example, if these tasks are used
- * to modify any state in common (such as writing a file due to a button click),
- * there are no guarantees on the order of the modifications.
- * Without careful work it is possible in rare cases for the newer version
- * of the data to be over-written by an older one, leading to obscure data
- * loss and stability issues. Such changes are best
- * executed in serial; to guarantee such work is serialized regardless of
- * platform version you can use this function with {@link #SERIAL_EXECUTOR}.
- *
- *
This method must be invoked on the UI thread.
- *
- * @param exec The executor to use. {@link #THREAD_POOL_EXECUTOR} is available as a
- * convenient process-wide thread pool for tasks that are loosely coupled.
- * @param params The parameters of the task.
- *
- * @return This instance of AsyncTask.
- *
- * @throws IllegalStateException If {@link #getStatus()} returns either
- * {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
- *
- * @see #execute(Object[])
- */
- public final AsyncTask executeOnExecutor(Executor exec,
- Params... params) {
- if (mStatus != Status.PENDING) {
- switch (mStatus) {
- case RUNNING:
- throw new IllegalStateException("Cannot execute task:"
- + " the task is already running.");
- case FINISHED:
- throw new IllegalStateException("Cannot execute task:"
- + " the task has already been executed "
- + "(a task can be executed only once)");
- }
- }
-
- mStatus = Status.RUNNING;
-
- onPreExecute();
-
- mWorker.mParams = params;
- exec.execute(mFuture);
-
- return this;
- }
-
- /**
- * Convenience version of {@link #execute(Object...)} for use with
- * a simple Runnable object. See {@link #execute(Object[])} for more
- * information on the order of execution.
- *
- * @see #execute(Object[])
- * @see #executeOnExecutor(java.util.concurrent.Executor, Object[])
- */
- public static void execute(Runnable runnable) {
- sDefaultExecutor.execute(runnable);
- }
-
- /**
- * This method can be invoked from {@link #doInBackground} to
- * publish updates on the UI thread while the background computation is
- * still running. Each call to this method will trigger the execution of
- * {@link #onProgressUpdate} on the UI thread.
- *
- * {@link #onProgressUpdate} will note be called if the task has been
- * canceled.
- *
- * @param values The progress values to update the UI with.
- *
- * @see #onProgressUpdate
- * @see #doInBackground
- */
- protected final void publishProgress(Progress... values) {
- if (!isCancelled()) {
- sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
- new AsyncTaskResult