├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── libraries │ └── support_v4_19_0_0.xml ├── misc.xml ├── modules.xml ├── scopes │ └── scope_settings.xml └── vcs.xml ├── AsyncAndroid.iml ├── AsyncAndroid ├── .gitignore ├── AsyncAndroid-AsyncAndroid.iml ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── packt │ │ └── asyncandroid │ │ ├── CompatibleActivity.java │ │ ├── LaunchActivity.java │ │ ├── SafeAsyncTask.java │ │ ├── SquareImage.java │ │ ├── SquareLayout.java │ │ ├── Streams.java │ │ ├── chapter1 │ │ ├── example1 │ │ │ └── ANRActivity.java │ │ └── example2 │ │ │ └── ChoreographerActivity.java │ │ ├── chapter2 │ │ ├── AsyncTaskMedleyActivity.java │ │ ├── PrimeCalculator.java │ │ ├── example1 │ │ │ ├── Example1Activity.java │ │ │ └── PrimesTask.java │ │ ├── example2 │ │ │ ├── Example2Activity.java │ │ │ └── PrimesTask.java │ │ ├── example3 │ │ │ ├── Example3Activity.java │ │ │ └── PrimesTask.java │ │ ├── example4 │ │ │ ├── Example4Activity.java │ │ │ └── PrimesTask.java │ │ ├── example5 │ │ │ ├── AsyncListener.java │ │ │ ├── Example5Activity.java │ │ │ └── PrimesFragment.java │ │ └── example6 │ │ │ └── Example6Activity.java │ │ ├── chapter3 │ │ ├── example1 │ │ │ ├── ExplicitHandlerPrimesActivity.java │ │ │ └── ViewHandlerPrimesActivity.java │ │ ├── example2 │ │ │ └── PostDelayedActivity.java │ │ ├── example3 │ │ │ └── EchoActivity.java │ │ ├── example4 │ │ │ └── HandlerThreadActivity.java │ │ └── example5 │ │ │ ├── CompassActivity.java │ │ │ └── CompassView.java │ │ ├── chapter4 │ │ ├── ThumbnailLoader.java │ │ ├── example1 │ │ │ └── ThumbnailActivity.java │ │ ├── example2 │ │ │ ├── MediaCursorAdapter.java │ │ │ └── MediaStoreActivity.java │ │ ├── example3 │ │ │ ├── MediaCursorAdapter.java │ │ │ ├── MediaStoreActivity.java │ │ │ └── ThumbnailCallbacks.java │ │ ├── example4 │ │ │ ├── PrimeView.java │ │ │ └── PrimesActivity.java │ │ └── example5 │ │ │ └── FileListActivity.java │ │ ├── chapter5 │ │ ├── example1 │ │ │ ├── PendingIntentPrimesActivity.java │ │ │ └── PendingIntentPrimesIntentService.java │ │ ├── example2 │ │ │ ├── NotifyingPrimesActivity.java │ │ │ └── NotifyingPrimesIntentService.java │ │ ├── example3 │ │ │ ├── MessageSendingPrimesActivity.java │ │ │ └── MessageSendingPrimesIntentService.java │ │ ├── example4 │ │ │ ├── BroadcastReceivingPrimesActivity.java │ │ │ └── BroadcastingPrimesIntentService.java │ │ └── example5 │ │ │ ├── ImageUploader.java │ │ │ ├── MediaCursorAdapter.java │ │ │ ├── ThumbnailCallbacks.java │ │ │ ├── ThumbnailLoader.java │ │ │ ├── UploadIntentService.java │ │ │ └── UploadPhotoActivity.java │ │ ├── chapter6 │ │ ├── ConcurrentDownloadService.java │ │ ├── ConcurrentIntentService.java │ │ ├── LocalDownloadCache.java │ │ ├── SimpleDownloader.java │ │ ├── example1 │ │ │ ├── PrimesActivity.java │ │ │ └── PrimesConcurrentIntentService.java │ │ ├── example2 │ │ │ ├── LocalPrimesActivity.java │ │ │ └── LocalPrimesService.java │ │ ├── example3 │ │ │ ├── MessageReceivingPrimesActivity.java │ │ │ └── MessageSendingPrimesService.java │ │ ├── example4 │ │ │ ├── BroadcastReceivingPrimesActivity.java │ │ │ └── BroadcastingPrimesService.java │ │ ├── example5 │ │ │ └── DownloadActivity.java │ │ └── example6 │ │ │ ├── DownloadTask.java │ │ │ ├── NasaImageOfTheDayActivity.java │ │ │ ├── NasaRSS.java │ │ │ └── NasaRSSParser.java │ │ └── chapter7 │ │ ├── example1 │ │ ├── AlarmReceiver.java │ │ └── StaticReceiverAlarmActivity.java │ │ ├── example2 │ │ └── DynamicReceiverAlarmActivity.java │ │ ├── example3 │ │ ├── AlarmSettingActivity.java │ │ └── AsyncBroadcastReceiver.java │ │ ├── example4 │ │ └── SetServiceAlarmActivity.java │ │ ├── example5 │ │ ├── AlarmReceiver.java │ │ ├── AwakeIntentService.java │ │ ├── AwakePrimesIntentService.java │ │ └── SetBroadcastAlarmActivity.java │ │ └── example6 │ │ └── SetActivityAlarmActivity.java │ └── res │ ├── drawable-hdpi │ └── ic_launcher.png │ ├── drawable-mdpi │ └── ic_launcher.png │ ├── drawable-xhdpi │ └── ic_launcher.png │ ├── drawable-xxhdpi │ └── ic_launcher.png │ ├── layout │ ├── book_activity_cell.xml │ ├── book_layout.xml │ ├── ch1_example1_layout.xml │ ├── ch1_example2_layout.xml │ ├── ch2_example6_layout.xml │ ├── ch2_example_layout.xml │ ├── ch2_medley_layout.xml │ ├── ch3_example1a_layout.xml │ ├── ch3_example1b_layout.xml │ ├── ch3_example2_layout.xml │ ├── ch3_example3_layout.xml │ ├── ch3_example4_layout.xml │ ├── ch3_example5_compass_layout.xml │ ├── ch4_example1_layout.xml │ ├── ch4_example2_cell.xml │ ├── ch4_example2_layout.xml │ ├── ch4_example3_cell.xml │ ├── ch4_example3_layout.xml │ ├── ch4_example4_layout.xml │ ├── ch4_example5_cell.xml │ ├── ch4_example5_layout.xml │ ├── ch5_example5_cell.xml │ ├── ch5_example5_layout.xml │ ├── ch5_example_layout.xml │ ├── ch6_example5_layout.xml │ ├── ch6_example6_layout.xml │ ├── ch6_example6_row_img_left.xml │ ├── ch6_example6_row_img_right.xml │ ├── ch6_example_layout.xml │ ├── ch7_example1_layout.xml │ ├── ch7_example2_layout.xml │ ├── ch7_example3_layout.xml │ ├── ch7_example4_layout.xml │ ├── ch7_example5_layout.xml │ └── ch7_example6_layout.xml │ ├── values-land │ └── dimens.xml │ ├── values-port │ └── dimens.xml │ ├── values-small-land │ └── dimens.xml │ ├── values-small-port │ └── dimens.xml │ ├── values-v11 │ └── styles.xml │ ├── values-v14 │ └── styles.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── README.md ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build 3 | /local.properties 4 | /.idea/workspace.xml 5 | .DS_Store 6 | *.apk 7 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | AsyncAndroid -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/libraries/support_v4_19_0_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 24 | 25 | 26 | 27 | 28 | 29 | Android API 19 Platform 30 | 31 | 36 | 37 | 38 | 39 | 40 | 41 | 1.7.0_07 42 | 43 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/scopes/scope_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /AsyncAndroid/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /AsyncAndroid/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | } 5 | dependencies { 6 | classpath 'com.android.tools.build:gradle:1.0.0-rc2' 7 | } 8 | } 9 | apply plugin: 'android' 10 | 11 | repositories { 12 | mavenCentral() 13 | } 14 | 15 | android { 16 | compileSdkVersion 19 17 | buildToolsVersion '19.1.0' 18 | 19 | defaultConfig { 20 | minSdkVersion 7 21 | targetSdkVersion 19 22 | } 23 | } 24 | 25 | dependencies { 26 | compile 'com.android.support:support-v4:19.0.0' 27 | } 28 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/CompatibleActivity.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid; 2 | 3 | import android.os.Bundle; 4 | import android.support.v4.app.FragmentActivity; 5 | 6 | /** 7 | * Adds support for isChangingConfigurations when minSdkVersion 8 | * targets api-levels below 11. 9 | * 10 | * Unfortunately onSaveInstanceState is invoked AFTER onPause, 11 | * so on platforms below 11 isChangingConfigurations will only 12 | * report correctly in onStop() or onDestroy(). 13 | */ 14 | public class CompatibleActivity extends FragmentActivity { 15 | 16 | private boolean isConfigChange; 17 | 18 | @Override 19 | protected void onSaveInstanceState(Bundle outState) { 20 | super.onSaveInstanceState(outState); 21 | isConfigChange = true; 22 | } 23 | 24 | @Override 25 | public boolean isChangingConfigurations() { 26 | if (android.os.Build.VERSION.SDK_INT >= 11) 27 | return super.isChangingConfigurations(); 28 | else 29 | return isConfigChange; 30 | } 31 | 32 | @Override 33 | protected void onStop() { 34 | super.onStop(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/SafeAsyncTask.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid; 2 | 3 | import android.os.AsyncTask; 4 | import android.util.Log; 5 | 6 | public abstract class SafeAsyncTask 7 | extends AsyncTask> { 8 | 9 | static class Result { 10 | private T result; 11 | private Exception exc; 12 | } 13 | 14 | protected abstract R doSafelyInBackground(Void... params) throws Exception; 15 | 16 | @Override 17 | protected final Result doInBackground(Void... params) { 18 | Result result = new Result(); 19 | try { 20 | result.result = doSafelyInBackground(params); 21 | } catch (Exception exc) { 22 | result.exc = exc; 23 | } 24 | return result; 25 | } 26 | 27 | @Override 28 | protected final void onPostExecute(Result result) { 29 | if (result.exc != null) { 30 | onCompletedWithException(result.exc); 31 | } else { 32 | onCompletedWithResult(result.result); 33 | } 34 | } 35 | 36 | @Override 37 | protected final void onCancelled(Result result) { 38 | onCancelledWithResult(result.result); 39 | } 40 | 41 | // override me if you want to handle exceptions 42 | protected void onCompletedWithException(Exception exc) { 43 | Log.e(LaunchActivity.TAG, exc.getMessage(), exc); 44 | } 45 | 46 | // override me if you want to handle the result 47 | protected void onCompletedWithResult(R result) { 48 | } 49 | 50 | // override me if you to handle the partial result 51 | // but _don't_ call super if you override 52 | protected void onCancelledWithResult(R result) { 53 | onCancelled(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/SquareImage.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.ImageView; 6 | 7 | public class SquareImage extends ImageView { 8 | 9 | public SquareImage(Context context, AttributeSet attrs) { 10 | super(context, attrs); 11 | } 12 | 13 | @Override 14 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 15 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 16 | setMeasuredDimension(getMeasuredWidth(), getMeasuredWidth()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/SquareLayout.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.LinearLayout; 6 | 7 | public class SquareLayout extends LinearLayout { 8 | 9 | public SquareLayout(Context context, AttributeSet attrs) { 10 | super(context, attrs); 11 | } 12 | 13 | @Override 14 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 15 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 16 | setMeasuredDimension(getMeasuredWidth(), getMeasuredWidth()); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/Streams.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid; 2 | 3 | import android.util.Log; 4 | 5 | import java.io.Closeable; 6 | import java.io.IOException; 7 | 8 | public class Streams { 9 | 10 | public static void close(Closeable... streams) { 11 | for (Closeable c : streams) { 12 | close(c); 13 | } 14 | } 15 | 16 | public static void close(Closeable stream) { 17 | try { 18 | if (stream != null) 19 | stream.close(); 20 | } catch (IOException anExc) { 21 | Log.w(LaunchActivity.TAG, "problem closing stream", anExc); 22 | } 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter1/example1/ANRActivity.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter1.example1; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.view.View; 6 | import android.widget.Button; 7 | 8 | import com.packt.asyncandroid.R; 9 | 10 | /** 11 | * DELIBERATELY trigger's an Application Not Responding dialog, 12 | * thereby crashing the containing app. 13 | */ 14 | public class ANRActivity extends Activity { 15 | @Override 16 | protected void onCreate(Bundle savedInstanceState) { 17 | super.onCreate(savedInstanceState); 18 | 19 | setContentView(R.layout.ch1_example1_layout); 20 | 21 | makeEvil((Button)findViewById(R.id.button1)); 22 | makeEvil((Button)findViewById(R.id.button2)); 23 | makeEvil((Button)findViewById(R.id.button3)); 24 | } 25 | 26 | private void makeEvil(Button button) { 27 | button.setOnClickListener(new View.OnClickListener() { 28 | @Override 29 | public void onClick(View v) { 30 | try { 31 | Thread.sleep(6000L); 32 | } catch (InterruptedException anExc) { 33 | anExc.printStackTrace(); 34 | } 35 | } 36 | }); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter1/example2/ChoreographerActivity.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter1.example2; 2 | 3 | import android.app.Activity; 4 | import android.graphics.Canvas; 5 | import android.os.Bundle; 6 | import android.view.ViewGroup; 7 | import android.widget.TextView; 8 | 9 | import com.packt.asyncandroid.R; 10 | 11 | public class ChoreographerActivity extends Activity { 12 | 13 | @Override 14 | protected void onCreate(Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | 17 | setContentView(R.layout.ch1_example2_layout); 18 | 19 | ViewGroup root = (ViewGroup) findViewById(R.id.root); 20 | 21 | root.addView(new TextView(this){ 22 | @Override 23 | protected void onDraw(Canvas canvas) { 24 | super.onDraw(canvas); 25 | long sleep = (long)(Math.random() * 1000L); 26 | setText("" + sleep); 27 | try { 28 | Thread.sleep(sleep); 29 | } catch (Exception exc) {} 30 | } 31 | }); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter2/PrimeCalculator.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter2; 2 | 3 | import java.math.BigInteger; 4 | 5 | public class PrimeCalculator { 6 | 7 | interface ProgressListener { 8 | public void onProgress(int percent); 9 | } 10 | 11 | interface Status { 12 | public boolean isCalculationCancelled(); 13 | } 14 | 15 | private ProgressMeter meter; 16 | 17 | public PrimeCalculator(long timeoutMillis) { 18 | meter = new ProgressMeter(timeoutMillis); 19 | } 20 | 21 | public BigInteger findHighestProbablePrime() { 22 | return findHighestProbablePrime(new NoOpProgressListener()); 23 | } 24 | 25 | public BigInteger findHighestProbablePrime(ProgressListener listener) { 26 | return findHighestProbablePrime(listener, new UnknownCancellationStatus()); 27 | } 28 | 29 | public BigInteger findHighestProbablePrime(ProgressListener listener, Status status) { 30 | meter.start(); 31 | BigInteger prime = new BigInteger("2"); 32 | 33 | while(!meter.isComplete() && !status.isCalculationCancelled()) { 34 | prime = prime.nextProbablePrime(); 35 | listener.onProgress(meter.calculateProgress()); 36 | } 37 | 38 | return prime; 39 | } 40 | 41 | private static class ProgressMeter 42 | { 43 | long startTime, onePercent; 44 | int percentComplete; 45 | 46 | public ProgressMeter(long timeoutMillis) { 47 | onePercent = timeoutMillis / 100L; 48 | percentComplete = 0; 49 | } 50 | 51 | public void start() { 52 | startTime = System.currentTimeMillis(); 53 | } 54 | 55 | public int calculateProgress() { 56 | long now = System.currentTimeMillis(); 57 | return percentComplete = (int)((now - startTime) / onePercent); 58 | } 59 | 60 | public boolean isComplete() { 61 | return percentComplete >= 100; 62 | } 63 | } 64 | 65 | private static class NoOpProgressListener implements ProgressListener { 66 | public void onProgress(int aPercent){ 67 | // deliberately doing nothing 68 | } 69 | } 70 | 71 | private static class UnknownCancellationStatus implements Status { 72 | public boolean isCalculationCancelled() { 73 | return false; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter2/example1/Example1Activity.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter2.example1; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.view.View; 6 | import android.widget.Button; 7 | import android.widget.TextView; 8 | 9 | import com.packt.asyncandroid.R; 10 | 11 | public class Example1Activity extends Activity { 12 | 13 | @Override 14 | protected void onCreate(Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | setContentView(R.layout.ch2_example_layout); 17 | 18 | Button goButton = (Button) findViewById(R.id.go); 19 | goButton.setOnClickListener(new View.OnClickListener() { 20 | @Override 21 | public void onClick(View view) { 22 | // find the nth probable prime in the background using AsyncTask 23 | new PrimesTask((TextView) findViewById(R.id.result)).execute(500); 24 | } 25 | }); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter2/example1/PrimesTask.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter2.example1; 2 | 3 | import android.os.AsyncTask; 4 | import android.widget.TextView; 5 | 6 | import java.math.BigInteger; 7 | 8 | public class PrimesTask extends AsyncTask { 9 | private TextView resultView; 10 | 11 | public PrimesTask(TextView resultView) { 12 | this.resultView = resultView; 13 | } 14 | 15 | @Override 16 | protected BigInteger doInBackground(Integer... params) { 17 | int primeToFind = params[0]; 18 | BigInteger prime = new BigInteger("2"); 19 | for (int i=0; i { 13 | private Context ctx; 14 | private ProgressDialog progress; 15 | private TextView resultView; 16 | 17 | public PrimesTask(Context ctx, TextView resultView) { 18 | this.ctx = ctx; 19 | this.resultView = resultView; 20 | } 21 | 22 | @Override 23 | protected void onPreExecute() { 24 | progress = new ProgressDialog(ctx); 25 | progress.setTitle(R.string.calculating); 26 | progress.setCancelable(false); 27 | progress.show(); 28 | } 29 | 30 | @Override 31 | protected BigInteger doInBackground(Integer... params) { 32 | int primeToFind = params[0]; 33 | BigInteger prime = new BigInteger("2"); 34 | for (int i=0; i { 13 | private Context ctx; 14 | private ProgressDialog progress; 15 | private TextView resultView; 16 | 17 | public PrimesTask(Context ctx, TextView resultView) { 18 | this.ctx = ctx; 19 | this.resultView = resultView; 20 | } 21 | 22 | @Override 23 | protected void onPreExecute() { 24 | progress = new ProgressDialog(ctx); 25 | progress.setTitle(R.string.calculating); 26 | progress.setCancelable(false); 27 | progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); 28 | progress.setProgress(0); 29 | progress.setMax(100); 30 | progress.show(); 31 | } 32 | 33 | @Override 34 | protected BigInteger doInBackground(Integer... params) { 35 | int primeToFind = params[0]; 36 | BigInteger prime = new BigInteger("2"); 37 | for (int i=0; i { 14 | private Context ctx; 15 | private ProgressDialog progress; 16 | private TextView resultView; 17 | 18 | public PrimesTask(Context ctx, TextView resultView) { 19 | this.ctx = ctx; 20 | this.resultView = resultView; 21 | } 22 | 23 | @Override 24 | protected void onPreExecute() { 25 | progress = new ProgressDialog(ctx); 26 | progress.setTitle(R.string.calculating); 27 | progress.setCancelable(true); 28 | progress.setOnCancelListener(new DialogInterface.OnCancelListener() { 29 | @Override 30 | public void onCancel(DialogInterface dialog) { 31 | PrimesTask.this.cancel(false); 32 | } 33 | }); 34 | progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); 35 | progress.setProgress(0); 36 | progress.setMax(100); 37 | progress.show(); 38 | } 39 | 40 | @Override 41 | protected BigInteger doInBackground(Integer... params) { 42 | int primeToFind = params[0]; 43 | BigInteger prime = new BigInteger("2"); 44 | for (int i=0; i { 4 | void onPreExecute(); 5 | void onProgressUpdate(Progress... progress); 6 | void onPostExecute(Result result); 7 | void onCancelled(Result result); 8 | } 9 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter2/example5/Example5Activity.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter2.example5; 2 | 3 | import android.app.ProgressDialog; 4 | import android.content.DialogInterface; 5 | import android.os.Bundle; 6 | import android.support.v4.app.FragmentActivity; 7 | import android.support.v4.app.FragmentManager; 8 | import android.support.v4.app.FragmentTransaction; 9 | import android.view.View; 10 | import android.widget.Button; 11 | import android.widget.TextView; 12 | 13 | import com.packt.asyncandroid.R; 14 | 15 | import java.math.BigInteger; 16 | 17 | public class Example5Activity extends FragmentActivity 18 | implements AsyncListener { 19 | 20 | public static final String PRIMES = "primes"; 21 | private ProgressDialog dialog; 22 | private TextView resultView; 23 | private Button goButton; 24 | 25 | @Override 26 | protected void onCreate(Bundle savedInstanceState) { 27 | super.onCreate(savedInstanceState); 28 | setContentView(R.layout.ch2_example_layout); 29 | ((TextView)findViewById(R.id.title)).setText(R.string.ch2_ex5); 30 | ((TextView)findViewById(R.id.description)).setText(R.string.ch2_ex5_desc); 31 | 32 | resultView = (TextView)findViewById(R.id.result); 33 | goButton = (Button)findViewById(R.id.go); 34 | goButton.setOnClickListener(new View.OnClickListener(){ 35 | @Override 36 | public void onClick(View v) { 37 | PrimesFragment primes = (PrimesFragment) 38 | getSupportFragmentManager().findFragmentByTag(PRIMES); 39 | 40 | if (primes == null) { 41 | primes = new PrimesFragment(); 42 | FragmentTransaction transaction = 43 | getSupportFragmentManager().beginTransaction(); 44 | transaction.add(primes, PRIMES); 45 | transaction.commit(); 46 | } 47 | } 48 | }); 49 | } 50 | 51 | public void onPreExecute() { 52 | onProgressUpdate(0); 53 | } 54 | 55 | public void onProgressUpdate(Integer... progress) { 56 | if (dialog == null) { 57 | prepareProgressDialog(); 58 | } 59 | dialog.setProgress(progress[0]); 60 | } 61 | 62 | public void onPostExecute(BigInteger result) { 63 | resultView.setText(result.toString()); 64 | cleanUp(); 65 | } 66 | 67 | public void onCancelled(BigInteger result) { 68 | resultView.setText("cancelled at " + result); 69 | cleanUp(); 70 | } 71 | 72 | private void prepareProgressDialog() { 73 | dialog = new ProgressDialog(this); 74 | dialog.setTitle(R.string.calculating); 75 | dialog.setCancelable(true); 76 | dialog.setOnCancelListener(new DialogInterface.OnCancelListener() { 77 | @Override 78 | public void onCancel(DialogInterface dialog) { 79 | PrimesFragment primes = (PrimesFragment) 80 | getSupportFragmentManager().findFragmentByTag(PRIMES); 81 | primes.cancel(); 82 | } 83 | }); 84 | dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); 85 | dialog.setProgress(0); 86 | dialog.setMax(100); 87 | dialog.show(); 88 | } 89 | 90 | private void cleanUp() { 91 | dialog.dismiss(); 92 | dialog = null; 93 | FragmentManager fm = getSupportFragmentManager(); 94 | PrimesFragment primes = (PrimesFragment) fm.findFragmentByTag(PRIMES); 95 | fm.beginTransaction().remove(primes).commit(); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter2/example5/PrimesFragment.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter2.example5; 2 | 3 | import android.app.Activity; 4 | import android.os.AsyncTask; 5 | import android.os.Bundle; 6 | import android.support.v4.app.Fragment; 7 | 8 | import java.math.BigInteger; 9 | 10 | public class PrimesFragment extends Fragment { 11 | 12 | private AsyncListener listener; 13 | private PrimesTask task; 14 | 15 | @Override 16 | public void onCreate(Bundle savedInstanceState) { 17 | super.onCreate(savedInstanceState); 18 | setRetainInstance(true); 19 | task = new PrimesTask(); 20 | task.execute(2000); 21 | } 22 | 23 | @Override 24 | public void onAttach(Activity activity) { 25 | super.onAttach(activity); 26 | listener = (AsyncListener)activity; 27 | } 28 | 29 | @Override 30 | public void onDetach() { 31 | super.onDetach(); 32 | listener = null; 33 | } 34 | 35 | public void cancel() { 36 | task.cancel(false); 37 | } 38 | 39 | class PrimesTask extends AsyncTask { 40 | @Override 41 | protected void onPreExecute() { 42 | if (listener != null) listener.onPreExecute(); 43 | } 44 | 45 | @Override 46 | protected BigInteger doInBackground(Integer... params) { 47 | int primeToFind = params[0]; 48 | BigInteger prime = new BigInteger("2"); 49 | for (int i=0; i { 33 | private static Random random = new Random(); 34 | 35 | private TextView resultView; 36 | 37 | public ExceptionalPrimesTask(TextView resultView) { 38 | this.resultView = resultView; 39 | } 40 | 41 | @Override 42 | protected BigInteger doSafelyInBackground(Void... params) throws Exception { 43 | if (random.nextBoolean()) { 44 | throw new RuntimeException("bang"); 45 | } else { 46 | return new BigInteger("12345"); 47 | } 48 | } 49 | 50 | @Override 51 | protected void onCompletedWithResult(BigInteger result) { 52 | resultView.setText(result.toString()); 53 | } 54 | 55 | @Override 56 | protected void onCompletedWithException(Exception exc) { 57 | resultView.setText(exc.getMessage()); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter3/example1/ExplicitHandlerPrimesActivity.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter3.example1; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.os.Handler; 6 | import android.view.View; 7 | import android.widget.Button; 8 | import android.widget.TextView; 9 | 10 | import com.packt.asyncandroid.R; 11 | 12 | import java.math.BigInteger; 13 | 14 | /** 15 | * Illustrates creating a Handler attached to the main thread's Looper, 16 | * and posting Runnable's to the Handler for the main thread to execute. 17 | */ 18 | public class ExplicitHandlerPrimesActivity extends Activity { 19 | 20 | private Handler handler; 21 | 22 | @Override 23 | protected void onCreate(Bundle savedInstanceState) { 24 | super.onCreate(savedInstanceState); 25 | 26 | setContentView(R.layout.ch3_example1a_layout); 27 | 28 | // create a Handler bound to the main thread 29 | handler = new Handler(); 30 | 31 | final TextView resultView = (TextView) findViewById(R.id.result); 32 | 33 | Button goButton = (Button) findViewById(R.id.go); 34 | goButton.setOnClickListener(new View.OnClickListener() { 35 | @Override 36 | public void onClick(View view) { 37 | // find the nth probable prime in the 38 | // background using a simple thread 39 | resultView.setText(R.string.calculating); 40 | new PrimeCalculator(500, resultView, handler).start(); 41 | } 42 | }); 43 | } 44 | 45 | private static class PrimeCalculator extends Thread { 46 | 47 | private int primeToFind; 48 | private TextView resultView; 49 | private Handler handler; 50 | 51 | public PrimeCalculator(int primeToFind, TextView resultView, Handler handler) { 52 | this.handler = handler; 53 | this.resultView = resultView; 54 | this.primeToFind = primeToFind; 55 | // make sure to reduce the thread priority so we 56 | // don't starve the main thread! 57 | setPriority(Thread.MIN_PRIORITY); 58 | } 59 | 60 | @Override 61 | public void run() { 62 | BigInteger prime = new BigInteger("2"); 63 | for (int i=0; i { 17 | 18 | private static final int LOADER_ID = "thumb_loader".hashCode(); 19 | 20 | private Integer mediaId; 21 | private ImageView thumb; 22 | 23 | @Override 24 | protected void onCreate(Bundle savedInstanceState) { 25 | super.onCreate(savedInstanceState); 26 | setContentView(R.layout.ch4_example1_layout); 27 | thumb = (ImageView) findViewById(R.id.thumb); 28 | mediaId = getMediaIdFromIntent(getIntent()); 29 | if (mediaId != null) 30 | getSupportLoaderManager().initLoader(LOADER_ID, null, this); 31 | } 32 | 33 | @Override 34 | protected void onDestroy() { 35 | super.onDestroy(); 36 | if (isFinishing()) { 37 | getSupportLoaderManager().destroyLoader(LOADER_ID); 38 | } 39 | } 40 | 41 | @Override 42 | public Loader onCreateLoader(int i, Bundle bundle) { 43 | return new ThumbnailLoader(getApplicationContext(), mediaId); 44 | } 45 | 46 | @Override 47 | public void onLoadFinished(Loader loader, Bitmap bitmap) { 48 | thumb.setImageBitmap(bitmap); 49 | } 50 | 51 | @Override 52 | public void onLoaderReset(Loader loader) { 53 | // we don't need to do anything here. 54 | } 55 | 56 | private Integer getMediaIdFromIntent(Intent intent) { 57 | if (Intent.ACTION_SEND.equals(intent.getAction())) { 58 | Uri uri = intent.getParcelableExtra(Intent.EXTRA_STREAM); 59 | return new Integer(uri.getLastPathSegment()); 60 | } else { 61 | return null; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter4/example2/MediaCursorAdapter.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter4.example2; 2 | 3 | import android.content.Context; 4 | import android.provider.MediaStore; 5 | import android.support.v4.widget.SimpleCursorAdapter; 6 | 7 | import com.packt.asyncandroid.R; 8 | 9 | public class MediaCursorAdapter extends SimpleCursorAdapter { 10 | private static String[] FIELDS = new String[]{ 11 | MediaStore.Images.Media._ID, 12 | MediaStore.Images.Media.DISPLAY_NAME 13 | }; 14 | 15 | private static int[] VIEWS = new int[]{ 16 | R.id.media_id, R.id.display_name 17 | }; 18 | 19 | public MediaCursorAdapter(Context context) { 20 | super(context, R.layout.ch4_example2_cell, null, FIELDS, VIEWS, 0); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter4/example2/MediaStoreActivity.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter4.example2; 2 | 3 | import android.database.Cursor; 4 | import android.os.Bundle; 5 | import android.provider.MediaStore; 6 | import android.support.v4.app.LoaderManager; 7 | import android.support.v4.content.CursorLoader; 8 | import android.support.v4.content.Loader; 9 | import android.widget.GridView; 10 | 11 | import com.packt.asyncandroid.R; 12 | import com.packt.asyncandroid.CompatibleActivity; 13 | 14 | public class MediaStoreActivity extends CompatibleActivity 15 | implements LoaderManager.LoaderCallbacks { 16 | 17 | public static final int MS_LOADER = "ms_crsr".hashCode(); 18 | 19 | private MediaCursorAdapter adapter; 20 | 21 | @Override 22 | protected void onCreate(Bundle savedInstanceState) { 23 | super.onCreate(savedInstanceState); 24 | 25 | setContentView(R.layout.ch4_example2_layout); 26 | 27 | adapter = new MediaCursorAdapter(getApplicationContext()); 28 | 29 | GridView grid = (GridView)findViewById(R.id.grid); 30 | grid.setAdapter(adapter); 31 | 32 | getSupportLoaderManager() 33 | .initLoader(MS_LOADER, null, this); 34 | } 35 | 36 | @Override 37 | public CursorLoader onCreateLoader(int id, Bundle bundle) { 38 | return new CursorLoader(this, 39 | MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 40 | new String[]{ 41 | MediaStore.Images.Media._ID, 42 | MediaStore.Images.Media.DISPLAY_NAME 43 | }, "", null, null); 44 | } 45 | 46 | @Override 47 | public void onLoadFinished(Loader loader, Cursor media) { 48 | adapter.changeCursor(media); 49 | } 50 | 51 | @Override 52 | public void onLoaderReset(Loader loader) { 53 | adapter.changeCursor(null); 54 | } 55 | 56 | @Override 57 | protected void onStop() { 58 | super.onStop(); 59 | 60 | if (isFinishing()) { 61 | // if we don't want to use the loaders in other activities 62 | // this is our last chance to clean it up. 63 | getSupportLoaderManager().destroyLoader(MS_LOADER); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter4/example3/MediaCursorAdapter.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter4.example3; 2 | 3 | import android.content.Context; 4 | import android.database.Cursor; 5 | import android.provider.MediaStore; 6 | import android.support.v4.app.LoaderManager; 7 | import android.support.v4.content.Loader; 8 | import android.support.v4.widget.CursorAdapter; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.ImageView; 13 | 14 | import com.packt.asyncandroid.R; 15 | import com.packt.asyncandroid.chapter4.ThumbnailLoader; 16 | 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | public class MediaCursorAdapter extends CursorAdapter { 21 | 22 | private LoaderManager mgr; 23 | private LayoutInflater inf; 24 | private int count; 25 | private List ids; 26 | 27 | public MediaCursorAdapter(Context ctx, LoaderManager mgr) { 28 | super(ctx.getApplicationContext(), null, true); 29 | this.mgr = mgr; 30 | inf = (LayoutInflater) ctx. 31 | getSystemService(Context.LAYOUT_INFLATER_SERVICE); 32 | ids = new ArrayList(); 33 | } 34 | 35 | @Override 36 | public View newView(final Context ctx, Cursor crsr, ViewGroup parent) { 37 | ImageView view = (ImageView) inf. 38 | inflate(R.layout.ch4_example3_cell, parent, false); 39 | view.setId(MediaCursorAdapter.class.hashCode() + ++count); 40 | mgr.initLoader( 41 | view.getId(), null, new ThumbnailCallbacks(ctx, view)); 42 | ids.add(view.getId()); // remember the id, so we can clean it up later 43 | return view; 44 | } 45 | 46 | @Override 47 | public void bindView(View view, final Context context, Cursor cursor) { 48 | Loader l = mgr.getLoader(view.getId()); 49 | ThumbnailLoader loader = (ThumbnailLoader) l; 50 | 51 | Integer mediaId = cursor.getInt(cursor.getColumnIndex(MediaStore.Images.Media._ID)); 52 | 53 | // optimisation for orientation changes 54 | // that would otherwise do unnecessary work 55 | if (!mediaId.equals(loader.getMediaId())) { 56 | ImageView image = (ImageView) view; 57 | image.setImageBitmap(null); 58 | loader.setMediaId(mediaId); 59 | } 60 | } 61 | 62 | public void destroyLoaders() { 63 | for (Integer id : ids) 64 | mgr.destroyLoader(id); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter4/example3/MediaStoreActivity.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter4.example3; 2 | 3 | import android.database.Cursor; 4 | import android.os.Bundle; 5 | import android.provider.MediaStore; 6 | import android.support.v4.app.LoaderManager; 7 | import android.support.v4.content.CursorLoader; 8 | import android.support.v4.content.Loader; 9 | import android.widget.GridView; 10 | 11 | import com.packt.asyncandroid.R; 12 | import com.packt.asyncandroid.CompatibleActivity; 13 | 14 | public class MediaStoreActivity extends CompatibleActivity 15 | implements LoaderManager.LoaderCallbacks { 16 | 17 | private static final String TAG = "asyncandroid"; 18 | public static final int MS_LOADER = "ms_crsr".hashCode(); 19 | 20 | private MediaCursorAdapter adapter; 21 | 22 | @Override 23 | protected void onCreate(Bundle savedInstanceState) { 24 | super.onCreate(savedInstanceState); 25 | 26 | setContentView(R.layout.ch4_example3_layout); 27 | 28 | adapter = new MediaCursorAdapter( 29 | getApplicationContext(), 30 | getSupportLoaderManager()); 31 | 32 | GridView grid = (GridView)findViewById(R.id.grid); 33 | grid.setAdapter(adapter); 34 | 35 | getSupportLoaderManager().initLoader(MS_LOADER, null, this); 36 | } 37 | 38 | @Override 39 | public CursorLoader onCreateLoader(int id, Bundle bundle) { 40 | return new CursorLoader(this, 41 | MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 42 | new String[]{ 43 | MediaStore.Images.Media._ID, 44 | MediaStore.Images.Media.DISPLAY_NAME 45 | }, "", null, null); 46 | } 47 | 48 | @Override 49 | public void onLoadFinished(Loader loader, Cursor media) { 50 | adapter.changeCursor(media); 51 | } 52 | 53 | @Override 54 | public void onLoaderReset(Loader loader) { 55 | adapter.changeCursor(null); 56 | } 57 | 58 | @Override 59 | protected void onStop() { 60 | super.onStop(); 61 | 62 | if (isFinishing()) { 63 | // if we don't want to use these loaders in other activities 64 | // this is our last chance to clean them up. 65 | getSupportLoaderManager().destroyLoader(MS_LOADER); 66 | adapter.destroyLoaders(); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter4/example3/ThumbnailCallbacks.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter4.example3; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.Color; 6 | import android.graphics.drawable.BitmapDrawable; 7 | import android.graphics.drawable.ColorDrawable; 8 | import android.graphics.drawable.Drawable; 9 | import android.graphics.drawable.TransitionDrawable; 10 | import android.os.Bundle; 11 | import android.support.v4.app.LoaderManager; 12 | import android.support.v4.content.Loader; 13 | import android.widget.ImageView; 14 | 15 | import com.packt.asyncandroid.chapter4.ThumbnailLoader; 16 | 17 | /** 18 | * LoaderCallbacks implementation that expects to receive a Bitmap in onLoadFinished 19 | * and will display the bitmap with a nice fade-in effect. 20 | */ 21 | public class ThumbnailCallbacks implements LoaderManager.LoaderCallbacks { 22 | private Context context; 23 | private ImageView image; 24 | 25 | public ThumbnailCallbacks(Context context, ImageView image) { 26 | // ensuring that we always only keep a handle on the Application Context 27 | // so that we don't leak references to the Activity! 28 | this.context = context.getApplicationContext(); 29 | this.image = image; 30 | } 31 | 32 | @Override 33 | public Loader onCreateLoader(int i, Bundle bundle) { 34 | return new ThumbnailLoader(context); 35 | } 36 | 37 | @Override 38 | public void onLoadFinished(Loader loader, Bitmap b) { 39 | // we could just set the bitmap to the imageview, but 40 | // lets create a drawable that fades from transparent to 41 | // our bitmap, for a bit of extra swankiness... 42 | final TransitionDrawable drawable = 43 | new TransitionDrawable(new Drawable[] { 44 | new ColorDrawable(Color.TRANSPARENT), 45 | new BitmapDrawable(context.getResources(), b) 46 | }); 47 | 48 | // set our fade-in drawable to the image view 49 | image.setImageDrawable(drawable); 50 | 51 | // fade in over 0.2 seconds 52 | drawable.startTransition(200); 53 | } 54 | 55 | @Override 56 | public void onLoaderReset(Loader loader) { 57 | // nothing much for us to do here. 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter4/example4/PrimeView.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter4.example4; 2 | 3 | import android.content.Context; 4 | import android.util.TypedValue; 5 | import android.view.Gravity; 6 | import android.widget.TextView; 7 | 8 | public class PrimeView extends TextView { 9 | 10 | public PrimeView(Context context) { 11 | super(context); 12 | 13 | setGravity(Gravity.CENTER); 14 | setTextSize(TypedValue.COMPLEX_UNIT_DIP, 40); 15 | } 16 | 17 | @Override 18 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 19 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 20 | 21 | // make our view square! 22 | setMeasuredDimension(getMeasuredWidth(), getMeasuredWidth()); 23 | } 24 | 25 | public void setValue(String value) { 26 | setText(value); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter5/example1/PendingIntentPrimesActivity.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter5.example1; 2 | 3 | import android.app.Activity; 4 | import android.app.PendingIntent; 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.view.View; 8 | import android.widget.Button; 9 | import android.widget.TextView; 10 | import android.widget.Toast; 11 | 12 | import com.packt.asyncandroid.R; 13 | 14 | import java.math.BigInteger; 15 | 16 | public class PendingIntentPrimesActivity extends Activity{ 17 | 18 | private static final int REQUEST_CODE = 0; 19 | 20 | @Override 21 | protected void onCreate(Bundle savedInstanceState) { 22 | super.onCreate(savedInstanceState); 23 | 24 | setContentView(R.layout.ch5_example_layout); 25 | ((TextView)findViewById(R.id.title)).setText(R.string.ch5_ex1); 26 | ((TextView)findViewById(R.id.description)).setText(R.string.ch5_ex1_desc); 27 | 28 | Button go = (Button)findViewById(R.id.go); 29 | go.setOnClickListener(new View.OnClickListener() { 30 | @Override 31 | public void onClick(View v) { 32 | TextView input = (TextView) findViewById(R.id.prime_to_find); 33 | String value = input.getText().toString(); 34 | if (value.matches("[1-9]+[0-9]*")) { 35 | // if the value is a number, trigger the loader to 36 | // reload when appropriate. 37 | triggerIntentService(Integer.parseInt(value)); 38 | } else { 39 | Toast.makeText(PendingIntentPrimesActivity.this, "not a number!", 5000).show(); 40 | } 41 | } 42 | }); 43 | } 44 | 45 | @Override 46 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 47 | if (resultCode == PendingIntentPrimesIntentService.RESULT_CODE) { 48 | BigInteger result = (BigInteger) data.getSerializableExtra( 49 | PendingIntentPrimesIntentService.RESULT); 50 | TextView view = (TextView)findViewById(R.id.result); 51 | view.setText(result.toString()); 52 | } 53 | super.onActivityResult(requestCode, resultCode, data); 54 | } 55 | 56 | private void triggerIntentService(int primeToFind) { 57 | PendingIntent pendingResult = createPendingResult( 58 | REQUEST_CODE, new Intent(), 0); 59 | Intent intent = new Intent(this, PendingIntentPrimesIntentService.class); 60 | intent.putExtra(PendingIntentPrimesIntentService.PARAM, primeToFind); 61 | intent.putExtra(PendingIntentPrimesIntentService.PENDING_RESULT, pendingResult); 62 | startService(intent); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter5/example1/PendingIntentPrimesIntentService.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter5.example1; 2 | 3 | import android.app.IntentService; 4 | import android.app.PendingIntent; 5 | import android.content.Intent; 6 | import android.util.Log; 7 | 8 | import com.packt.asyncandroid.LaunchActivity; 9 | 10 | import java.math.BigInteger; 11 | 12 | public class PendingIntentPrimesIntentService extends IntentService { 13 | 14 | public static final String PARAM = "prime_to_find"; 15 | public static final String PENDING_RESULT = "pending_result"; 16 | public static final String RESULT = "result"; 17 | public static final int RESULT_CODE = "nth_prime".hashCode(); 18 | public static final int INVALID = "invalid".hashCode(); 19 | 20 | public PendingIntentPrimesIntentService() { 21 | super("primes"); 22 | } 23 | 24 | @Override 25 | protected void onHandleIntent(Intent intent) { 26 | PendingIntent reply = intent.getParcelableExtra(PENDING_RESULT); 27 | int n = intent.getIntExtra(PARAM, -1); 28 | try { 29 | if (n < 2) { 30 | reply.send(INVALID); 31 | } else { 32 | BigInteger prime = new BigInteger("2"); 33 | Intent result = new Intent(); 34 | for (int i=0; i= 200) && (conn.getResponseCode() < 400)) { 67 | Log.i(TAG, "Uploaded Successfully!"); 68 | return true; 69 | } else { 70 | Log.w(TAG, "Upload failed with return-code " + conn.getResponseCode()); 71 | return false; 72 | } 73 | } catch (IOException exc) { 74 | Log.e(TAG, "upload failed", exc); 75 | return false; 76 | } finally { 77 | conn.disconnect(); 78 | } 79 | } 80 | 81 | private int getContentLength(Uri uri) 82 | throws IOException { 83 | ParcelFileDescriptor pfd = null; 84 | try { 85 | pfd = content.openFileDescriptor(uri, "r"); 86 | return (int)pfd.getStatSize(); 87 | } finally { 88 | if (pfd != null) 89 | pfd.close(); 90 | } 91 | } 92 | 93 | private void pump(InputStream in, OutputStream out, ProgressCallback callback, int len) 94 | throws IOException { 95 | try { 96 | int length,i=0,size=256; 97 | byte[] buffer = new byte[size]; 98 | 99 | while ((length = in.read(buffer)) > -1) { 100 | out.write(buffer, 0, length); 101 | out.flush(); 102 | callback.onProgress(len, ++i*size); 103 | } 104 | } finally { 105 | Streams.close(in, out); 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter5/example5/MediaCursorAdapter.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter5.example5; 2 | 3 | import android.content.Context; 4 | import android.database.Cursor; 5 | import android.provider.MediaStore; 6 | import android.support.v4.app.LoaderManager; 7 | import android.support.v4.content.Loader; 8 | import android.support.v4.widget.CursorAdapter; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.ImageView; 13 | 14 | import com.packt.asyncandroid.R; 15 | 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | 19 | public class MediaCursorAdapter extends CursorAdapter { 20 | 21 | private LoaderManager mgr; 22 | private LayoutInflater inf; 23 | private int count; 24 | private List ids; 25 | 26 | public MediaCursorAdapter(Context ctx, LoaderManager mgr) { 27 | super(ctx.getApplicationContext(), null, true); 28 | this.mgr = mgr; 29 | inf = (LayoutInflater) ctx. 30 | getSystemService(Context.LAYOUT_INFLATER_SERVICE); 31 | ids = new ArrayList(); 32 | } 33 | 34 | @Override 35 | public View newView(final Context ctx, Cursor crsr, ViewGroup parent) { 36 | ImageView view = (ImageView) inf. 37 | inflate(R.layout.ch5_example5_cell, parent, false); 38 | view.setId(MediaCursorAdapter.class.hashCode() + ++count); 39 | mgr.initLoader( 40 | view.getId(), null, new ThumbnailCallbacks(ctx, view)); 41 | ids.add(view.getId()); // remember the id, so we can clean it up later 42 | return view; 43 | } 44 | 45 | @Override 46 | public void bindView(View view, final Context context, Cursor cursor) { 47 | Loader l = mgr.getLoader(view.getId()); 48 | ThumbnailLoader loader = (ThumbnailLoader) l; 49 | 50 | Integer mediaId = cursor.getInt(cursor.getColumnIndex(MediaStore.Images.Media._ID)); 51 | 52 | ImageView image = (ImageView) view; 53 | image.setImageBitmap(null); 54 | loader.setMediaId(mediaId); 55 | } 56 | 57 | public void destroyLoaders() { 58 | for (Integer id : ids) 59 | mgr.destroyLoader(id); 60 | } 61 | } 62 | 63 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter5/example5/ThumbnailCallbacks.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter5.example5; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.Color; 6 | import android.graphics.drawable.BitmapDrawable; 7 | import android.graphics.drawable.ColorDrawable; 8 | import android.graphics.drawable.Drawable; 9 | import android.graphics.drawable.TransitionDrawable; 10 | import android.os.Bundle; 11 | import android.support.v4.app.LoaderManager; 12 | import android.support.v4.content.Loader; 13 | import android.widget.ImageView; 14 | 15 | /** 16 | * LoaderCallbacks implementation that expects to receive a Bitmap in onLoadFinished 17 | * and will display the bitmap with a nice fade-in effect. 18 | */ 19 | public class ThumbnailCallbacks implements LoaderManager.LoaderCallbacks { 20 | private Context context; 21 | private ImageView image; 22 | 23 | public ThumbnailCallbacks(Context context, ImageView image) { 24 | // ensuring that we always only keep a handle on the Application Context 25 | // so that we don't leak references to the Activity! 26 | this.context = context.getApplicationContext(); 27 | this.image = image; 28 | } 29 | 30 | @Override 31 | public Loader onCreateLoader(int i, Bundle bundle) { 32 | return new ThumbnailLoader(context); 33 | } 34 | 35 | @Override 36 | public void onLoadFinished(Loader loader, Bitmap b) { 37 | // we could just set the bitmap to the imageview, but 38 | // lets create a drawable that fades from transparent to 39 | // our bitmap, for a bit of extra swankiness... 40 | final TransitionDrawable drawable = 41 | new TransitionDrawable(new Drawable[] { 42 | new ColorDrawable(Color.TRANSPARENT), 43 | new BitmapDrawable(context.getResources(), b) 44 | }); 45 | 46 | // set our fade-in drawable to the image view 47 | image.setImageDrawable(drawable); 48 | 49 | // fade in over 0.2 seconds 50 | drawable.startTransition(200); 51 | } 52 | 53 | @Override 54 | public void onLoaderReset(Loader loader) { 55 | // nothing much for us to do here. 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter5/example5/ThumbnailLoader.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter5.example5; 2 | 3 | import android.content.ContentResolver; 4 | import android.content.Context; 5 | import android.graphics.Bitmap; 6 | import android.provider.MediaStore; 7 | import android.support.v4.content.AsyncTaskLoader; 8 | 9 | /** 10 | * An AsyncTaskLoader implementation that loads a Bitmap thumbnail 11 | * in the background from the MediaStore. 12 | * 13 | * There are two good reasons to load these thumbnails off the UI thread: 14 | * 15 | * (1) Loading bitmaps entails IO, which we should always try to keep 16 | * off the main thread if we want our apps to be responsive. 17 | * 18 | * (2) The first time we request a thumbnail from the MediaStore it is 19 | * quite possibly going to have to be created by scaling down the 20 | * original image - this is a potentially expensive operation and 21 | * we definitely don't want to do that on the main thread! 22 | * 23 | * Notice that: 24 | * 25 | * (i) The Loader does not know or care what the bitmap will be used for. 26 | * Its job is purely to load the image, to cache the image for future 27 | * use, and to properly clean up in the lifecycle callbacks. 28 | * 29 | * (ii) Bitmaps are "special", in that their data is managed off-heap, and 30 | * is potentially large. We will clean them up expediently by calling 31 | * recycle when the bitmap is no longer needed. 32 | */ 33 | public class ThumbnailLoader extends AsyncTaskLoader { 34 | 35 | private Bitmap data, old; 36 | private Integer mediaId; 37 | 38 | public ThumbnailLoader(Context context, Integer mediaId) { 39 | super(context); 40 | this.mediaId = mediaId; 41 | } 42 | 43 | public ThumbnailLoader(Context context) { 44 | super(context); 45 | } 46 | 47 | public Integer getMediaId() { 48 | return mediaId; 49 | } 50 | 51 | public void setMediaId(Integer mediaId) { 52 | this.mediaId = mediaId; 53 | // notify the machinery of AsyncTaskLoader that something 54 | // has changed, so that it will trigger a reload when 55 | // necessary. 56 | onContentChanged(); 57 | } 58 | 59 | @Override 60 | public Bitmap loadInBackground() { 61 | ContentResolver res = getContext().getContentResolver(); 62 | if (mediaId != null) { 63 | return MediaStore.Images.Thumbnails.getThumbnail( 64 | res, mediaId, MediaStore.Images.Thumbnails.MINI_KIND, null); 65 | } 66 | return null; 67 | } 68 | 69 | @Override 70 | protected void onStartLoading() { 71 | // if we already have a loaded bitmap, deliver 72 | // it to the callbacks... 73 | if (data != null) 74 | deliverResult(data); 75 | 76 | // if we've been notified that the content 77 | // changed, or if we don't currently have 78 | // a bitmap at all ... 79 | if (takeContentChanged() || data == null) { 80 | // kick-start loading of the new data 81 | forceLoad(); 82 | } 83 | } 84 | 85 | @Override 86 | public void deliverResult(Bitmap data) { 87 | super.deliverResult(this.data = data); 88 | } 89 | 90 | @Override 91 | protected void onStopLoading() { 92 | // cancel and make sure to clean up 93 | cancelLoad(); 94 | } 95 | 96 | @Override 97 | public void onCanceled(Bitmap data) { 98 | // loading was cancelled before we got 99 | // here, so we must discard the loaded 100 | // bitmap (if there was one). 101 | if (data != null) 102 | data.recycle(); 103 | old = null; 104 | } 105 | 106 | @Override 107 | protected void onReset() { 108 | // if we have a bitmap, make sure it is 109 | // recycled asap. 110 | if (data != null) { 111 | data.recycle(); 112 | data = null; 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter5/example5/UploadIntentService.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter5.example5; 2 | 3 | import android.app.IntentService; 4 | import android.app.NotificationManager; 5 | import android.content.Context; 6 | import android.content.Intent; 7 | import android.net.Uri; 8 | import android.support.v4.app.NotificationCompat; 9 | 10 | import com.packt.asyncandroid.R; 11 | 12 | public class UploadIntentService extends IntentService { 13 | 14 | private ImageUploader uploader; 15 | 16 | public UploadIntentService() { 17 | super("upload"); 18 | } 19 | 20 | @Override 21 | public void onCreate() { 22 | super.onCreate(); 23 | uploader = new ImageUploader(getContentResolver()); 24 | } 25 | 26 | @Override 27 | protected void onHandleIntent(Intent intent) { 28 | Uri data = intent.getData(); 29 | int id = Integer.parseInt(data.getLastPathSegment()); 30 | String msg = String.format("Uploading %s.jpg",id); 31 | ProgressNotificationCallback progress = 32 | new ProgressNotificationCallback(this, id, msg); 33 | if (uploader.upload(data, progress)) { 34 | progress.onComplete( 35 | String.format("Successfully uploaded %s.jpg", id)); 36 | } else { 37 | progress.onComplete( 38 | String.format("Upload failed %s.jpg", id)); 39 | } 40 | } 41 | 42 | private class ProgressNotificationCallback 43 | implements ImageUploader.ProgressCallback { 44 | 45 | private NotificationCompat.Builder builder; 46 | private NotificationManager nm; 47 | private int id, prev; 48 | 49 | public ProgressNotificationCallback(Context ctx, int id, String msg) { 50 | this.id = id; 51 | prev = 0; 52 | builder = new NotificationCompat.Builder(ctx) 53 | .setSmallIcon(android.R.drawable.stat_sys_upload_done) 54 | .setContentTitle(getString(R.string.upload_service)) 55 | .setContentText(msg) 56 | .setProgress(100,0,false); 57 | nm = (NotificationManager) 58 | getSystemService(Context.NOTIFICATION_SERVICE); 59 | nm.notify(id, builder.build()); 60 | } 61 | 62 | @Override 63 | public void onProgress(int max, int progress) { 64 | int percent = (int)((100f*progress)/max); 65 | if (percent > (prev + 5)) { 66 | builder.setProgress(100, percent, false); 67 | nm.notify(id, builder.build()); 68 | prev = percent; 69 | } 70 | } 71 | 72 | @Override 73 | public void onComplete(String msg) { 74 | builder.setProgress(0, 0, false); 75 | builder.setContentText(msg); 76 | nm.notify(id, builder.build()); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter5/example5/UploadPhotoActivity.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter5.example5; 2 | 3 | import android.content.Intent; 4 | import android.database.Cursor; 5 | import android.net.Uri; 6 | import android.os.Bundle; 7 | import android.provider.MediaStore; 8 | import android.support.v4.app.LoaderManager; 9 | import android.support.v4.content.CursorLoader; 10 | import android.support.v4.content.Loader; 11 | import android.view.View; 12 | import android.widget.AdapterView; 13 | import android.widget.GridView; 14 | 15 | import com.packt.asyncandroid.CompatibleActivity; 16 | import com.packt.asyncandroid.R; 17 | 18 | public class UploadPhotoActivity extends CompatibleActivity 19 | implements LoaderManager.LoaderCallbacks { 20 | 21 | private static final String TAG = "asyncandroid"; 22 | public static final int MS_LOADER = "ms_crsr".hashCode(); 23 | 24 | private MediaCursorAdapter adapter; 25 | 26 | @Override 27 | protected void onCreate(Bundle savedInstanceState) { 28 | super.onCreate(savedInstanceState); 29 | 30 | setContentView(R.layout.ch5_example5_layout); 31 | 32 | adapter = new MediaCursorAdapter( 33 | getApplicationContext(), 34 | getSupportLoaderManager()); 35 | 36 | GridView grid = (GridView)findViewById(R.id.grid); 37 | grid.setAdapter(adapter); 38 | grid.setOnItemClickListener(new AdapterView.OnItemClickListener() { 39 | @Override 40 | public void onItemClick(AdapterView parent, View view, int position, long id) { 41 | Cursor cursor = (Cursor)adapter.getItem(position); 42 | int mediaId = cursor.getInt( 43 | cursor.getColumnIndex(MediaStore.Images.Media._ID)); 44 | Uri uri = Uri.withAppendedPath( 45 | MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 46 | Integer.toString(mediaId)); 47 | Intent intent = new Intent( 48 | UploadPhotoActivity.this, UploadIntentService.class); 49 | intent.setData(uri); 50 | startService(intent); 51 | } 52 | }); 53 | 54 | final CursorLoader loader = (CursorLoader) 55 | getSupportLoaderManager().initLoader(MS_LOADER, null, this); 56 | 57 | loader.setUpdateThrottle(10000L); 58 | } 59 | 60 | @Override 61 | public CursorLoader onCreateLoader(int id, Bundle bundle) { 62 | return new CursorLoader(this, 63 | MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 64 | new String[]{ 65 | MediaStore.Images.Media._ID, 66 | MediaStore.Images.Media.DISPLAY_NAME 67 | }, "", null, null); 68 | } 69 | 70 | @Override 71 | public void onLoadFinished(Loader loader, Cursor media) { 72 | adapter.changeCursor(media); 73 | } 74 | 75 | @Override 76 | public void onLoaderReset(Loader loader) { 77 | adapter.changeCursor(null); 78 | } 79 | 80 | @Override 81 | protected void onStop() { 82 | super.onStop(); 83 | 84 | if (isFinishing()) { 85 | // if we don't want to use these loaders in other activities 86 | // this is our last chance to clean them up. 87 | getSupportLoaderManager().destroyLoader(MS_LOADER); 88 | adapter.destroyLoaders(); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter6/ConcurrentDownloadService.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter6; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.net.Uri; 6 | import android.os.Message; 7 | import android.os.Messenger; 8 | import android.os.Process; 9 | import android.os.RemoteException; 10 | import android.util.Log; 11 | 12 | import com.packt.asyncandroid.LaunchActivity; 13 | 14 | import java.io.IOException; 15 | import java.util.concurrent.Executor; 16 | import java.util.concurrent.Executors; 17 | import java.util.concurrent.ThreadFactory; 18 | 19 | public class ConcurrentDownloadService extends ConcurrentIntentService { 20 | 21 | public static final int MAX_CONCURRENT_DOWNLOADS = 3; 22 | public static final Executor DOWNLOAD_THREAD_POOL = 23 | Executors.newFixedThreadPool( 24 | MAX_CONCURRENT_DOWNLOADS, new ThreadFactory(){ 25 | @Override 26 | public Thread newThread(Runnable r) { 27 | Thread t = new Thread(r); 28 | Process.setThreadPriority( 29 | Process.THREAD_PRIORITY_BACKGROUND); 30 | t.setName("download"); 31 | return t; 32 | } 33 | }); 34 | public static final String DOWNLOAD_FROM_URL = "from_url"; 35 | public static final String MESSENGER = "messenger"; 36 | public static final int SUCCESSFUL = "download_successful".hashCode(); 37 | public static final int FAILED = "download_failed".hashCode(); 38 | 39 | public static int startDownload(String url, Context ctx, Messenger messenger) { 40 | Intent intent = new Intent(ctx, ConcurrentDownloadService.class); 41 | intent.putExtra(ConcurrentDownloadService.DOWNLOAD_FROM_URL, url); 42 | intent.putExtra(ConcurrentDownloadService.REQUEST_ID, url.hashCode()); 43 | intent.putExtra(ConcurrentDownloadService.MESSENGER, messenger); 44 | ctx.startService(intent); 45 | return url.hashCode(); 46 | } 47 | 48 | private SimpleDownloader downloader; 49 | 50 | public ConcurrentDownloadService() { 51 | super(DOWNLOAD_THREAD_POOL); 52 | } 53 | 54 | @Override 55 | public void onCreate() { 56 | super.onCreate(); 57 | downloader = new SimpleDownloader(this); 58 | } 59 | 60 | @Override 61 | protected void onHandleIntent(Intent intent) { 62 | Messenger messenger = intent.getParcelableExtra(MESSENGER); 63 | String url = intent.getStringExtra(DOWNLOAD_FROM_URL); 64 | try { 65 | Uri local = downloader.download(url); 66 | sendMessage(messenger, SUCCESSFUL, url.hashCode(), local); 67 | } catch (IOException exc) { 68 | sendMessage(messenger, FAILED, url.hashCode(), null); 69 | } 70 | } 71 | 72 | private void sendMessage(Messenger messenger, int status, int requestId, Uri data) { 73 | try { 74 | messenger.send( 75 | Message.obtain(null, status, requestId, 0, data)); 76 | } catch (RemoteException exc) { 77 | Log.e(LaunchActivity.TAG, "unable to send success message to client."); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter6/ConcurrentIntentService.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter6; 2 | 3 | import android.app.Service; 4 | import android.content.Intent; 5 | import android.os.Handler; 6 | import android.os.IBinder; 7 | import android.os.Message; 8 | import android.util.Log; 9 | 10 | import com.packt.asyncandroid.LaunchActivity; 11 | 12 | import java.util.concurrent.Executor; 13 | 14 | /** 15 | * A Service that implements Intent-driven behavior - like IntentService, 16 | * but uses an ExecutorService to perform the background work instead of 17 | * IntentService's single worker thread, giving complete control over the 18 | * level of concurrency to the sub-class through its configuration of 19 | * the ExecutorService. 20 | * 21 | * Also like IntentService, ConcurrentIntentService will stop itself 22 | * when all pending tasks have completed, so there is no need for 23 | * clients to ever ask the service to stop. 24 | */ 25 | public abstract class ConcurrentIntentService extends Service { 26 | 27 | public static final String REQUEST_ID = "request_id"; 28 | 29 | private final CompletionHandler handler = new CompletionHandler(); 30 | private final Executor executor; 31 | private int counter; 32 | 33 | public ConcurrentIntentService(Executor executor) { 34 | this.executor = executor; 35 | } 36 | 37 | /** 38 | * Runs in the background using the ExecutorService. 39 | * 40 | * When all requests have been handled, this Service stops itself, 41 | * so you should not call {@link #stopSelf}. 42 | * 43 | * @param intent The value passed to {@link 44 | * android.content.Context#startService(android.content.Intent)}. 45 | */ 46 | protected abstract void onHandleIntent(Intent intent); 47 | 48 | @Override 49 | public final int onStartCommand(final Intent intent, int flags, int startId) { 50 | counter++; 51 | executor.execute(new Runnable(){ 52 | @Override 53 | public void run() { 54 | try { 55 | onHandleIntent(intent); 56 | } finally { 57 | handler.sendMessage(Message.obtain(handler)); 58 | } 59 | } 60 | }); 61 | return START_NOT_STICKY; 62 | } 63 | 64 | @Override 65 | public IBinder onBind(Intent intent) { 66 | return null; 67 | } 68 | 69 | private class CompletionHandler extends Handler { 70 | @Override 71 | public void handleMessage(Message msg) { 72 | if (--counter == 0) { 73 | Log.i(LaunchActivity.TAG, "no more tasks, stopping"); 74 | stopSelf(); 75 | } else { 76 | Log.i(LaunchActivity.TAG, counter + " active tasks"); 77 | } 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter6/LocalDownloadCache.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter6; 2 | 3 | import android.content.Context; 4 | import android.net.Uri; 5 | 6 | import java.io.BufferedOutputStream; 7 | import java.io.File; 8 | import java.io.FileOutputStream; 9 | import java.io.IOException; 10 | import java.io.OutputStream; 11 | 12 | /** 13 | * Very simple cache - most definitely not advised for 14 | * production use! 15 | */ 16 | public class LocalDownloadCache { 17 | 18 | public static final long FIVE_MINUTES = 5L * 60L * 1000L; 19 | 20 | private File dir; 21 | 22 | public LocalDownloadCache(Context ctx) { 23 | dir = ctx.getCacheDir(); 24 | } 25 | 26 | public boolean exists(String url) { 27 | File f = getCacheFile(url); 28 | if (f.exists()) { 29 | if (expired(f)) { 30 | f.delete(); 31 | return false; 32 | } else { 33 | return true; 34 | } 35 | } 36 | return false; 37 | } 38 | 39 | public Uri get(String url) 40 | throws IOException { 41 | File f = getCacheFile(url); 42 | return Uri.fromFile(f); 43 | } 44 | 45 | public OutputStream getOutputStream(String url) 46 | throws IOException { 47 | File f = getCacheFile(url); 48 | return new BufferedOutputStream(new FileOutputStream(f)); 49 | } 50 | 51 | private boolean expired(File f) { 52 | return System.currentTimeMillis() - f.lastModified() > FIVE_MINUTES; 53 | } 54 | 55 | private File getCacheFile(String url) { 56 | String name = url.substring(url.lastIndexOf("/")+1, url.length()); 57 | return new File(dir, url.hashCode() + "_" + name); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter6/SimpleDownloader.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter6; 2 | 3 | import android.content.Context; 4 | import android.net.Uri; 5 | 6 | import com.packt.asyncandroid.Streams; 7 | 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | import java.io.OutputStream; 11 | import java.net.HttpURLConnection; 12 | import java.net.URL; 13 | import java.util.concurrent.ConcurrentHashMap; 14 | 15 | public class SimpleDownloader { 16 | 17 | private LocalDownloadCache cache; 18 | private ConcurrentHashMap locks; 19 | 20 | public SimpleDownloader(Context ctx){ 21 | cache = new LocalDownloadCache(ctx); 22 | locks = new ConcurrentHashMap(); 23 | } 24 | 25 | public Uri download(String from) throws IOException { 26 | locks.putIfAbsent(from,from); 27 | from = locks.get(from); 28 | try { 29 | synchronized(from) { 30 | if (!cache.exists(from)) { 31 | doDownload(from); 32 | } 33 | return cache.get(from); 34 | } 35 | } finally { 36 | locks.remove(from); 37 | } 38 | } 39 | 40 | private void doDownload(String from) throws IOException { 41 | URL url = new URL(from); 42 | HttpURLConnection conn = (HttpURLConnection)url.openConnection(); 43 | try { 44 | InputStream in = conn.getInputStream(); 45 | OutputStream out = cache.getOutputStream(from); 46 | int length; 47 | byte[] buffer = new byte[1024]; 48 | while ((length = in.read(buffer)) > -1) { 49 | out.write(buffer, 0, length); 50 | out.flush(); 51 | } 52 | Streams.close(in, out); 53 | } finally { 54 | conn.disconnect(); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter6/example1/PrimesActivity.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter6.example1; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.os.Handler; 7 | import android.os.Message; 8 | import android.os.Messenger; 9 | import android.util.Log; 10 | import android.view.View; 11 | import android.widget.Button; 12 | import android.widget.LinearLayout; 13 | import android.widget.TextView; 14 | import android.widget.Toast; 15 | 16 | import com.packt.asyncandroid.LaunchActivity; 17 | import com.packt.asyncandroid.R; 18 | 19 | public class PrimesActivity extends Activity { 20 | 21 | private static PrimesHandler handler = new PrimesHandler(); 22 | private static Messenger messenger = new Messenger(handler); 23 | 24 | @Override 25 | protected void onCreate(Bundle savedInstanceState) { 26 | super.onCreate(savedInstanceState); 27 | 28 | setContentView(R.layout.ch6_example_layout); 29 | ((TextView)findViewById(R.id.title)).setText(R.string.ch6_ex1); 30 | ((TextView)findViewById(R.id.description)).setText(R.string.ch6_ex1_desc); 31 | 32 | Button go = (Button)findViewById(R.id.go); 33 | go.setOnClickListener(new View.OnClickListener() { 34 | @Override 35 | public void onClick(View v) { 36 | TextView input = (TextView) findViewById(R.id.prime_to_find); 37 | String[] values = input.getText().toString().split(",|\\s"); 38 | for (String value : values) { 39 | if (value.trim().matches("[1-9]+[0-9]*")) { 40 | triggerService(Integer.parseInt(value.trim())); 41 | } else { 42 | Toast.makeText(PrimesActivity.this, "not a number!", 5000).show(); 43 | } 44 | } 45 | } 46 | }); 47 | } 48 | 49 | @Override 50 | protected void onResume() { 51 | super.onResume(); 52 | handler.attach((LinearLayout)findViewById(R.id.results)); 53 | } 54 | 55 | @Override 56 | protected void onPause() { 57 | super.onPause(); 58 | handler.detach(); 59 | } 60 | 61 | private void triggerService(int primeToFind) { 62 | Intent intent = new Intent(this, PrimesConcurrentIntentService.class); 63 | intent.putExtra(PrimesConcurrentIntentService.PARAM, primeToFind); 64 | intent.putExtra(PrimesConcurrentIntentService.MSNGR, messenger); 65 | startService(intent); 66 | } 67 | 68 | private static class PrimesHandler extends Handler { 69 | private LinearLayout view; 70 | 71 | @Override 72 | public void handleMessage(Message message) { 73 | if (message.what == PrimesConcurrentIntentService.RESULT) { 74 | if (view != null) { 75 | TextView text = new TextView(view.getContext()); 76 | text.setText(message.arg1 + "th prime: " + message.obj.toString()); 77 | view.addView(text); 78 | } else { 79 | Log.i(LaunchActivity.TAG, "received a result, ignoring because we're detached"); 80 | } 81 | } else if (message.what == PrimesConcurrentIntentService.INVALID) { 82 | if (view != null) { 83 | TextView text = new TextView(view.getContext()); 84 | text.setText("Invalid request"); 85 | view.addView(text); 86 | } 87 | } else { 88 | super.handleMessage(message); 89 | } 90 | } 91 | 92 | public void attach(LinearLayout view) { 93 | this.view = view; 94 | } 95 | 96 | public void detach() { 97 | this.view = null; 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter6/example1/PrimesConcurrentIntentService.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter6.example1; 2 | 3 | import android.content.Intent; 4 | import android.os.Message; 5 | import android.os.Messenger; 6 | import android.os.RemoteException; 7 | import android.util.Log; 8 | 9 | import com.packt.asyncandroid.LaunchActivity; 10 | import com.packt.asyncandroid.chapter6.ConcurrentIntentService; 11 | 12 | import java.math.BigInteger; 13 | import java.util.concurrent.Executors; 14 | import java.util.concurrent.ThreadFactory; 15 | 16 | public class PrimesConcurrentIntentService extends ConcurrentIntentService { 17 | 18 | private static final int MAX_CONCURRENT_CALCULATIONS = 5; 19 | public static final String PARAM = "prime_to_find"; 20 | public static final String MSNGR = "messenger"; 21 | public static final int INVALID = "invalid".hashCode(); 22 | public static final int RESULT = "nth_prime".hashCode(); 23 | 24 | public PrimesConcurrentIntentService() { 25 | super(Executors.newFixedThreadPool( 26 | MAX_CONCURRENT_CALCULATIONS, 27 | new ThreadFactory(){ 28 | @Override 29 | public Thread newThread(Runnable r) { 30 | Thread t = new Thread(r); 31 | t.setPriority(Thread.MIN_PRIORITY); 32 | t.setName("download"); 33 | return t; 34 | } 35 | })); 36 | } 37 | 38 | @Override 39 | protected void onHandleIntent(Intent intent) { 40 | int primeToFind = intent.getIntExtra(PARAM, -1); 41 | Messenger messenger = intent.getParcelableExtra(MSNGR); 42 | try { 43 | if (primeToFind < 2) { 44 | messenger.send(Message.obtain(null, INVALID)); 45 | } else { 46 | messenger.send(Message.obtain(null, RESULT, primeToFind, 0, calculateNthPrime(primeToFind))); 47 | } 48 | } catch (RemoteException anExc) { 49 | Log.e(LaunchActivity.TAG, "Unable to send message", anExc); 50 | } 51 | } 52 | 53 | private BigInteger calculateNthPrime(int primeToFind) { 54 | BigInteger prime = new BigInteger("2"); 55 | for (int i=0; i maybeCallback = 43 | new WeakReference(activity); 44 | new AsyncTask(){ 45 | @Override 46 | protected BigInteger doInBackground(Void... params) { 47 | BigInteger prime = new BigInteger("2"); 48 | for (int i=0; i(){ 45 | @Override 46 | protected Void doInBackground(Void... params) { 47 | BigInteger prime = new BigInteger("2"); 48 | for (int i=0; i= 11 59 | } 60 | 61 | private void notifyUser(int primeToFind, String result) { 62 | String msg = String.format("The %sth prime is %s", 63 | primeToFind, result); 64 | NotificationCompat.Builder builder = 65 | new NotificationCompat.Builder(this) 66 | .setSmallIcon(android.R.drawable.stat_notify_chat) 67 | .setContentTitle(getString(R.string.primes_service)) 68 | .setContentText(msg); 69 | NotificationManager nm = (NotificationManager) 70 | getSystemService(Context.NOTIFICATION_SERVICE); 71 | nm.notify(primeToFind, builder.build()); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter6/example4/BroadcastingPrimesService.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter6.example4; 2 | 3 | import android.app.NotificationManager; 4 | import android.app.Service; 5 | import android.content.Context; 6 | import android.content.Intent; 7 | import android.os.AsyncTask; 8 | import android.os.Binder; 9 | import android.os.IBinder; 10 | import android.support.v4.app.NotificationCompat; 11 | import android.support.v4.content.LocalBroadcastManager; 12 | 13 | import com.packt.asyncandroid.R; 14 | 15 | import java.math.BigInteger; 16 | 17 | public class BroadcastingPrimesService extends Service { 18 | 19 | public static final String PRIMES_BROADCAST = "com.packt.CH6_PRIMES_BROADCAST"; 20 | public static final String HANDLED = "intent_handled"; 21 | public static final String RESULT = "nth_prime"; 22 | 23 | public class Access extends Binder { 24 | public BroadcastingPrimesService getService() { 25 | return BroadcastingPrimesService.this; 26 | } 27 | }; 28 | 29 | private final Access binder = new Access(); 30 | 31 | @Override 32 | public IBinder onBind(Intent intent) { 33 | return binder; 34 | } 35 | 36 | @Override 37 | public int onStartCommand(Intent intent, int flags, int startId) { 38 | return START_STICKY; 39 | } 40 | 41 | public void calculateNthPrime(final int n) { 42 | new AsyncTask(){ 43 | @Override 44 | protected BigInteger doInBackground(Void... params) { 45 | BigInteger prime = new BigInteger("2"); 46 | for (int i=0; i= 11 57 | } 58 | 59 | private boolean broadcastResult(String result) { 60 | Intent intent = new Intent(PRIMES_BROADCAST); 61 | intent.putExtra(RESULT, result); 62 | LocalBroadcastManager.getInstance(this). 63 | sendBroadcastSync(intent); 64 | return intent.getBooleanExtra(HANDLED, false); 65 | } 66 | 67 | private void notifyUser(int primeToFind, String result) { 68 | String msg = String.format("The %sth prime is %s", 69 | primeToFind, result); 70 | NotificationCompat.Builder builder = 71 | new NotificationCompat.Builder(this) 72 | .setSmallIcon(android.R.drawable.stat_notify_chat) 73 | .setContentTitle(getString(R.string.primes_service)) 74 | .setContentText(msg); 75 | NotificationManager nm = (NotificationManager) 76 | getSystemService(Context.NOTIFICATION_SERVICE); 77 | nm.notify(primeToFind, builder.build()); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter6/example5/DownloadActivity.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter6.example5; 2 | 3 | import android.app.Activity; 4 | import android.net.Uri; 5 | import android.os.Bundle; 6 | import android.os.Handler; 7 | import android.os.Message; 8 | import android.os.Messenger; 9 | import android.util.Log; 10 | import android.widget.ImageView; 11 | 12 | import com.packt.asyncandroid.LaunchActivity; 13 | import com.packt.asyncandroid.R; 14 | import com.packt.asyncandroid.chapter6.ConcurrentDownloadService; 15 | 16 | public class DownloadActivity extends Activity { 17 | 18 | public static final String URL = 19 | "http://www.nasa.gov/images/content/158270main_solarflare.jpg"; 20 | 21 | private static final BitmapHandler handler = new BitmapHandler(); 22 | private static final Messenger messenger = new Messenger(handler); 23 | 24 | @Override 25 | protected void onCreate(Bundle savedInstanceState) { 26 | super.onCreate(savedInstanceState); 27 | 28 | setContentView(R.layout.ch6_example5_layout); 29 | } 30 | 31 | @Override 32 | protected void onResume() { 33 | super.onResume(); 34 | 35 | handler.attach((ImageView)findViewById(R.id.img)); 36 | 37 | ConcurrentDownloadService.startDownload(URL, this, messenger); 38 | } 39 | 40 | @Override 41 | protected void onPause() { 42 | super.onPause(); 43 | 44 | handler.detach(); 45 | } 46 | 47 | private static class BitmapHandler extends Handler { 48 | private ImageView view; 49 | 50 | @Override 51 | public void handleMessage(Message message) { 52 | if (message.what == ConcurrentDownloadService.SUCCESSFUL) { 53 | if (view != null) 54 | view.setImageURI((Uri)message.obj); 55 | } else { 56 | Log.w(LaunchActivity.TAG, "startDownload failed :("); 57 | } 58 | } 59 | 60 | public void attach(ImageView view) { 61 | this.view = view; 62 | } 63 | 64 | public void detach() { 65 | this.view = null; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter6/example6/NasaImageOfTheDayActivity.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter6.example6; 2 | 3 | import android.app.Activity; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.net.Uri; 7 | import android.os.Bundle; 8 | import android.util.Log; 9 | import android.view.ViewGroup; 10 | import android.widget.ImageView; 11 | import android.widget.TextView; 12 | 13 | import com.packt.asyncandroid.LaunchActivity; 14 | import com.packt.asyncandroid.R; 15 | import com.packt.asyncandroid.Streams; 16 | 17 | import java.io.IOException; 18 | import java.io.InputStream; 19 | 20 | public class NasaImageOfTheDayActivity extends Activity { 21 | 22 | private static final String RSS_URL = "http://www.nasa.gov/rss/dyn/lg_image_of_the_day.rss"; 23 | private static NasaRSSParser parser = new NasaRSSParser(); 24 | 25 | @Override 26 | protected void onCreate(Bundle savedInstanceState) { 27 | super.onCreate(savedInstanceState); 28 | 29 | setContentView(R.layout.ch6_example6_layout); 30 | } 31 | 32 | @Override 33 | protected void onResume() { 34 | super.onResume(); 35 | 36 | downloadRSS(); 37 | } 38 | 39 | @Override 40 | protected void onPause() { 41 | super.onPause(); 42 | 43 | // prevent memory leaks by clearing the references 44 | // to the callbacks which, being non-static inner 45 | // classes, have an implicit reference to the Activity. 46 | DownloadTask.clearCallbacks(); 47 | } 48 | 49 | private void downloadRSS(){ 50 | new DownloadTask(RSS_URL) { 51 | @Override 52 | public NasaRSS convertInBackground(Uri data) 53 | throws Exception { 54 | InputStream in = null; 55 | try { 56 | in = openStream(data); 57 | return parser.parse(in); 58 | } finally { 59 | Streams.close(in); 60 | } 61 | } 62 | 63 | @Override 64 | public void onSuccess(NasaRSS rss) { 65 | for (int i=0; i(url) { 84 | @Override 85 | public Bitmap convertInBackground(Uri data) throws Exception { 86 | InputStream in = null; 87 | try { 88 | BitmapFactory.Options opts = new BitmapFactory.Options(); 89 | opts.inSampleSize = sampleSize; 90 | in = openStream(data); 91 | return BitmapFactory.decodeStream(in, null, opts); 92 | } finally { 93 | Streams.close(in); 94 | } 95 | } 96 | 97 | @Override 98 | public void onSuccess(Bitmap data) { 99 | ImageView image = (ImageView) 100 | getRow(i).findViewById(R.id.img); 101 | image.setImageBitmap(data); 102 | } 103 | }.execute(this); 104 | } 105 | 106 | private ViewGroup getRow(int i) { 107 | ViewGroup root = (ViewGroup)findViewById(R.id.root); 108 | return (ViewGroup)root.getChildAt(i); 109 | } 110 | 111 | private InputStream openStream(Uri uri) { 112 | try { 113 | return getContentResolver().openInputStream(uri); 114 | } catch (IOException exc) { 115 | Log.e(LaunchActivity.TAG, "bad uri?", exc); 116 | return null; 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter6/example6/NasaRSS.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter6.example6; 2 | 3 | import android.os.Parcel; 4 | import android.os.Parcelable; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | public class NasaRSS implements Parcelable { 10 | 11 | public static final Parcelable.Creator CREATOR = new Parcelable.Creator(){ 12 | @Override 13 | public NasaRSS createFromParcel(Parcel source) { 14 | return new NasaRSS(source); 15 | } 16 | 17 | @Override 18 | public NasaRSS[] newArray(int size) { 19 | return new NasaRSS[size]; 20 | } 21 | }; 22 | 23 | public static class Item { 24 | public String url; 25 | public String title; 26 | public Item(String url, String title) { 27 | this.url = url; 28 | this.title = title; 29 | } 30 | } 31 | 32 | private List items; 33 | 34 | public NasaRSS(Parcel parcel) { 35 | items = new ArrayList(); 36 | int len = parcel.readInt(); 37 | for (int i=0; i(); 45 | } 46 | 47 | public void add(String url, String title) { 48 | items.add(new Item(url, title)); 49 | } 50 | 51 | public int size() { 52 | return items.size(); 53 | } 54 | 55 | public Item get(int i){ 56 | return items.get(i); 57 | } 58 | 59 | @Override 60 | public int describeContents() { 61 | return 0; 62 | } 63 | 64 | @Override 65 | public void writeToParcel(Parcel dest, int flags) { 66 | dest.writeInt(items.size()); 67 | for (Item i : items) { 68 | dest.writeString(i.url); 69 | dest.writeString(i.title); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter6/example6/NasaRSSParser.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter6.example6; 2 | 3 | import org.xml.sax.Attributes; 4 | import org.xml.sax.InputSource; 5 | import org.xml.sax.SAXException; 6 | import org.xml.sax.XMLReader; 7 | import org.xml.sax.helpers.DefaultHandler; 8 | 9 | import java.io.InputStream; 10 | 11 | import javax.xml.parsers.SAXParser; 12 | import javax.xml.parsers.SAXParserFactory; 13 | 14 | public class NasaRSSParser { 15 | 16 | private SAXParserFactory factory; 17 | 18 | public NasaRSSParser(){ 19 | factory = SAXParserFactory.newInstance(); 20 | } 21 | 22 | public NasaRSS parse(InputStream in) 23 | throws Exception { 24 | SAXParser parser = factory.newSAXParser(); 25 | XMLReader reader = parser.getXMLReader(); 26 | NasaRSSHandler rss = new NasaRSSHandler(); 27 | reader.setContentHandler(rss); 28 | 29 | reader.parse(new InputSource(in)); 30 | return rss.result; 31 | } 32 | 33 | class NasaRSSHandler extends DefaultHandler { 34 | NasaRSS result = new NasaRSS(); 35 | 36 | private String el; 37 | private String url; 38 | private StringBuilder title = new StringBuilder(); 39 | 40 | @Override 41 | public void startElement( 42 | String uri, String localName, 43 | String qName, Attributes attributes 44 | ) throws SAXException { 45 | if ("item".equals(qName)) { 46 | title.setLength(0); 47 | url = null; 48 | } else if ("enclosure".equals(qName)) { 49 | url = attributes.getValue("url"); 50 | } 51 | el = localName; 52 | } 53 | 54 | @Override 55 | public void characters(char[] ch, int start, int length) throws SAXException { 56 | if ("title".equals(el)) 57 | title.append(ch,start,length); 58 | } 59 | 60 | @Override 61 | public void endElement(String uri, String localName, String qName) throws SAXException { 62 | if ("item".equals(localName) && url != null) { 63 | result.add(url, title.toString()); 64 | } 65 | } 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter7/example1/AlarmReceiver.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter7.example1; 2 | 3 | import android.app.NotificationManager; 4 | import android.content.BroadcastReceiver; 5 | import android.content.Context; 6 | import android.content.Intent; 7 | import android.support.v4.app.NotificationCompat; 8 | 9 | import com.packt.asyncandroid.R; 10 | 11 | public class AlarmReceiver extends BroadcastReceiver { 12 | 13 | public static final String MSG = "message"; 14 | 15 | @Override 16 | public void onReceive(Context context, Intent intent) { 17 | NotificationCompat.Builder builder = 18 | new NotificationCompat.Builder(context) 19 | .setSmallIcon(android.R.drawable.stat_notify_chat) 20 | .setContentTitle(context.getString(R.string.ch7_ex1)) 21 | .setContentText(intent.getStringExtra(MSG)); 22 | NotificationManager nm = (NotificationManager) 23 | context.getSystemService(Context.NOTIFICATION_SERVICE); 24 | nm.notify(R.string.ch7_ex1, builder.build()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter7/example1/StaticReceiverAlarmActivity.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter7.example1; 2 | 3 | import android.app.Activity; 4 | import android.app.AlarmManager; 5 | import android.app.PendingIntent; 6 | import android.content.Intent; 7 | import android.content.IntentFilter; 8 | import android.os.Bundle; 9 | import android.view.View; 10 | import android.widget.Button; 11 | 12 | import com.packt.asyncandroid.R; 13 | 14 | import java.util.concurrent.TimeUnit; 15 | 16 | public class StaticReceiverAlarmActivity extends Activity { 17 | 18 | private static final long FIVE_SECONDS = TimeUnit.SECONDS.toMillis(5); 19 | 20 | @Override 21 | protected void onCreate(Bundle savedInstanceState) { 22 | super.onCreate(savedInstanceState); 23 | 24 | setContentView(R.layout.ch7_example1_layout); 25 | 26 | Button schedule = (Button)findViewById(R.id.schedule); 27 | schedule.setOnClickListener(new View.OnClickListener() { 28 | @Override 29 | public void onClick(View v) { 30 | AlarmManager am = (AlarmManager) 31 | getSystemService(ALARM_SERVICE); 32 | am.set( 33 | AlarmManager.RTC, System.currentTimeMillis()+FIVE_SECONDS, 34 | createPendingIntent()); 35 | } 36 | }); 37 | 38 | Button unschedule = (Button)findViewById(R.id.unschedule); 39 | unschedule.setOnClickListener(new View.OnClickListener() { 40 | @Override 41 | public void onClick(View v) { 42 | AlarmManager am = (AlarmManager) 43 | getSystemService(ALARM_SERVICE); 44 | am.cancel(createPendingIntent()); 45 | } 46 | }); 47 | } 48 | 49 | private PendingIntent createPendingIntent() { 50 | Intent intent = new Intent("static_receiver"); 51 | intent.putExtra(AlarmReceiver.MSG, "Remember to try out the alarm examples!"); 52 | return PendingIntent.getBroadcast( 53 | this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter7/example3/AlarmSettingActivity.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter7.example3; 2 | 3 | import android.app.Activity; 4 | import android.app.AlarmManager; 5 | import android.app.PendingIntent; 6 | import android.content.Intent; 7 | import android.os.Bundle; 8 | import android.text.format.Time; 9 | import android.view.View; 10 | import android.widget.Button; 11 | import android.widget.EditText; 12 | 13 | import com.packt.asyncandroid.R; 14 | 15 | import java.util.Calendar; 16 | import java.util.Date; 17 | import java.util.concurrent.TimeUnit; 18 | 19 | public class AlarmSettingActivity extends Activity { 20 | 21 | private static final long THIRTY_SECONDS = TimeUnit.SECONDS.toMillis(30); 22 | 23 | @Override 24 | protected void onCreate(Bundle savedInstanceState) { 25 | super.onCreate(savedInstanceState); 26 | 27 | setContentView(R.layout.ch7_example3_layout); 28 | 29 | Button go = (Button) findViewById(R.id.go); 30 | go.setOnClickListener(new View.OnClickListener() { 31 | @Override 32 | public void onClick(View v) { 33 | EditText input = (EditText) findViewById(R.id.prime_to_find); 34 | String value = input.getText().toString(); 35 | if (value.matches("[1-9]+[0-9]*")) { 36 | Intent intent = new Intent("primes_async_receiver"); 37 | intent.putExtra( 38 | AsyncBroadcastReceiver.PRIME_TO_FIND, Integer.parseInt(value)); 39 | final PendingIntent pending = PendingIntent.getBroadcast( 40 | AlarmSettingActivity.this, 41 | 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); 42 | 43 | AlarmManager am = (AlarmManager) 44 | getSystemService(ALARM_SERVICE); 45 | 46 | Calendar calendar = Calendar.getInstance(); 47 | if (calendar.get(Calendar.HOUR_OF_DAY) >= 13) { 48 | calendar.add(Calendar.DATE, 1); 49 | } 50 | calendar.set(Calendar.HOUR_OF_DAY, 13); 51 | calendar.set(Calendar.MINUTE, 0); 52 | calendar.set(Calendar.SECOND, 0); 53 | 54 | System.out.println(calendar.getTime()); 55 | 56 | am.set(AlarmManager.RTC, System.currentTimeMillis()+THIRTY_SECONDS, pending); 57 | } 58 | } 59 | }); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/java/com/packt/asyncandroid/chapter7/example3/AsyncBroadcastReceiver.java: -------------------------------------------------------------------------------- 1 | package com.packt.asyncandroid.chapter7.example3; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.app.NotificationManager; 5 | import android.content.BroadcastReceiver; 6 | import android.content.Context; 7 | import android.content.Intent; 8 | import android.os.AsyncTask; 9 | import android.os.Build; 10 | import android.os.SystemClock; 11 | import android.support.v4.app.NotificationCompat; 12 | 13 | import com.packt.asyncandroid.R; 14 | 15 | import java.math.BigInteger; 16 | 17 | /** 18 | * Demonstrates a BroadcastReceiver using the "goAsync" method 19 | * introduced in API level 11. Note that we are still subject to 20 | * the 10 second budget, but we can work in the background instead 21 | * of on the main thread without worrying about being shut-down 22 | * when the onReceive method completes. 23 | * 24 | * We MUST call result.finish within our 10 second budget (give or 25 | * take) to terminate the receive otherwise the system will shut 26 | * us down with ANR, so this is not suitable for long running 27 | * tasks or things that have dependencies outside our control (e.g 28 | * data connection speeds). 29 | */ 30 | public class AsyncBroadcastReceiver extends BroadcastReceiver { 31 | 32 | public static final String PRIME_TO_FIND = "prime_to_find"; 33 | 34 | @SuppressLint("NewApi") 35 | @Override 36 | public void onReceive(final Context context, final Intent intent) { 37 | if (Build.VERSION.SDK_INT > 11) { 38 | final PendingResult result = goAsync(); 39 | final int n = intent.getIntExtra(PRIME_TO_FIND, 2); 40 | new AsyncTask(){ 41 | @Override 42 | protected BigInteger doInBackground(Void... params) { 43 | BigInteger prime = new BigInteger("2"); 44 | for (int i=0; i= 19) { 56 | am.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + FIFTEEN_SECONDS, pending); 57 | } else { 58 | am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + FIFTEEN_SECONDS, pending); 59 | } 60 | } 61 | }); 62 | 63 | Button getActivities = (Button) findViewById(R.id.get_activities); 64 | getActivities.setOnClickListener(new View.OnClickListener() { 65 | @Override 66 | public void onClick(View v) { 67 | Intent first = new Intent( 68 | SetActivityAlarmActivity.this, 69 | LaunchActivity.class); 70 | first.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP ); 71 | Intent second = new Intent( 72 | SetActivityAlarmActivity.this, 73 | SetActivityAlarmActivity.class); 74 | second.putExtra(ALARMED, true); 75 | 76 | final PendingIntent pending = PendingIntent.getActivities( 77 | SetActivityAlarmActivity.this, 0, 78 | new Intent[]{first, second}, 79 | PendingIntent.FLAG_UPDATE_CURRENT); 80 | 81 | AlarmManager am = (AlarmManager) 82 | getSystemService(ALARM_SERVICE); 83 | 84 | if (Build.VERSION.SDK_INT >= 19) { 85 | am.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + FIFTEEN_SECONDS, pending); 86 | } else { 87 | am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + FIFTEEN_SECONDS, pending); 88 | } 89 | } 90 | }); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveliles/AsyncAndroid/c56b0d04fca3afa6fe4e8836763163e9c62d550f/AsyncAndroid/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /AsyncAndroid/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveliles/AsyncAndroid/c56b0d04fca3afa6fe4e8836763163e9c62d550f/AsyncAndroid/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /AsyncAndroid/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveliles/AsyncAndroid/c56b0d04fca3afa6fe4e8836763163e9c62d550f/AsyncAndroid/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /AsyncAndroid/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveliles/AsyncAndroid/c56b0d04fca3afa6fe4e8836763163e9c62d550f/AsyncAndroid/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /AsyncAndroid/src/main/res/layout/book_activity_cell.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 15 | 16 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/res/layout/book_layout.xml: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /AsyncAndroid/src/main/res/layout/ch1_example1_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 17 | 18 | 23 | 24 | 29 | 30 |