Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

How-To Tutorials - Android Programming

62 Articles
article-image-common-asynctask-issues
Packt
20 Dec 2013
7 min read
Save for later

Common AsyncTask issues

Packt
20 Dec 2013
7 min read
(For more resources related to this topic, see here.) Fragmentation issues AsyncTask has evolved with new releases of the Android platform, resulting in behavior that varies with the platform of the device running the task, which is a part of the wider issue of fragmentation. The simple fact is that if we target a broad range of API levels, the execution characteristics of our AsyncTasks—and therefore, the behavior of our apps—can vary considerably on different devices. So what can we do to reduce the likelihood of encountering AsyncTask issues due to fragmentation? The most obvious approach is to deliberately target devices running at least Honeycomb, by setting a minSdkVersion of 11 in the Android Manifest file. This neatly puts us in the category of devices, which, by default, execute AsyncTasks serially, and therefore, much more predictably. However, this significantly reduces the market reach of our apps. At the time of writing in September 2013, more than 34 percent of Android devices in the wild run a version of Android in the danger zone between API levels 4 and 10. A second option is to design our code carefully and test exhaustively on a range of devices—always commendable practices of course, but as we've seen, concurrent programming is hard enough without the added complexity of fragmentation, and invariably, subtle bugs will remain. A third solution that has been suggested by the Android development community is to reimplement AsyncTaskin a package within your own project, then extend your own AsyncTask class instead of the SDK version. In this way, you are no longer at the mercy of the user's device platform, and can regain control of your AsyncTasks. Since the source code for AsyncTask is readily available, this is not difficult to do. Activity lifecycle issues Having deliberately moved any long-running tasks off the main thread, we've made our applications nice and responsive—the main thread is free to respond very quickly to any user interaction. Unfortunately, we have also created a potential problem for ourselves, because the main thread is able to finish the Activity before our background tasks complete. Activity might finish for many reasons, including configuration changes caused the by the user rotating the device (the default behavior of Activity on a change in orientation is to restart with an entirely new instance of the activity). If we continue processing a background task after the Activity has finished, we are probably doing unnecessary work, and therefore wasting CPU and other resources (including battery life), which could be put to better use. Also, any object references held by the AsyncTask will not be eligible for garbage collection until the task explicitly nulls those references or completes and is itself eligible for GC ( garbage collection ). Since our AsyncTask probably references the Activity or parts of the View hierarchy, we can easily leak a significant amount of memory in this way. A common usage of AsyncTask is to declare it as an anonymous inner class of the host Activity, which creates an implicit reference to the Activity and an even bigger memory leak. There are two approaches for preventing these resource wastage problems. Handling lifecycle issues with early cancellation First, and most obviously, we can synchronize our AsyncTask lifecycle with that of the Activity by canceling running tasks when our Activity is finishing. When an Activity finishes, its lifecycle callback methods are invoked on the main thread. We can check to see why the lifecycle method is being called, and if the Activity is finishing, cancel the background tasks. The most appropriate Activity lifecycle method for this is onPause, which is guaranteed to be called before the Activity finishes. protected void onPause() { super.onPause(); if ((task != null) && (isFinishing())) task.cancel(false); } If the Activity is not finishing—say because it has started another Activity and is still on the back stack—we might simply allow our background task to continue to completion. Handling lifecycle issues with retained headless fragments If the Activity is finishing because of a configuration change, it may still be useful to complete the background task and display the results in the restarted Activity. One pattern for achieving this is through the use of retained Fragments. Fragments were introduced to Android at API level 11, but are available through a support library to applications targeting earlier API levels. All of the downloadable examples use the support library, and target API levels 7 through 19. To use Fragments, our Activity must extend the FragmentActivity class. The Fragment lifecycle is closely bound to that of the host Activity, and a fragment will normally be disposed when the activity restarts. However, we can explicitly prevent this by invoking setRetainInstance (true) on our Fragment so that it survives across Activity restarts. Typically, a Fragment will be responsible for creating and managing at least a portion of the user interface of an Activity, but this is not mandatory. A Fragment that does not manage a view of its own is known as a headless Fragment. Isolating our AsyncTask in a retained headless Fragment makes it less likely that we will accidentally leak references to objects such as the View hierarchy, because the AsyncTask will no longer directly interact with the user interface. To demonstrate this, we'll start by defining an interface that our Activity will implement: public interface AsyncListener<Progress, Result> { void onPreExecute(); void onProgressUpdate(Progress... progress); void onPostExecute(Result result); void onCancelled(Result result); } Next, we'll create a retained headless Fragment, which wraps our AsyncTask. For brevity, doInBackground is omitted, as it is unchanged from the previous examples—see the downloadable samples for the complete code. public class PrimesFragment extends Fragment { private AsyncListener<Integer,BigInteger> listener; private PrimesTask task; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRetainInstance(true); task = new PrimesTask(); task.execute(2000); } public void onAttach(Activity activity) { super.onAttach(activity); listener = (AsyncListener<Integer,BigInteger>)activity; } public void onDetach() { super.onDetach(); listener = null; } class PrimesTask extends AsyncTask<Integer, Integer, BigInteger>{ protected void onPreExecute() { if (listener != null) listener.onPreExecute(); } protected void onProgressUpdate(Integer... values) { if (listener != null) listener.onProgressUpdate(values); } protected void onPostExecute(BigInteger result) { if (listener != null) listener.onPostExecute(result); } protected void onCancelled(BigInteger result) { if (listener != null) listener.onCancelled(result); } // … doInBackground elided for brevity … } } We're using the Fragment lifecycle methods (onAttach and onDetach) to add or remove the current Activity as a listener, and PrimesTask delegates directly to it from all of its main-thread callbacks. Now, all we need is the host Activity that implements AsyncListener and uses PrimesFragment to implement its long-running task. The full source code is available to download from the Packt Publishing website, so we'll just take a look at the highlights. First, the code in the button's OnClickListener now checks to see if Fragment already exists, and only creates one if it is missing: FragmentManager fm = getSupportFragmentManager(); PrimesFragment primes = (PrimesFragment)fm.findFragmentByTag("primes"); if (primes == null) { primes = new PrimesFragment(); FragmentTransaction transaction = fm.beginTransaction(); transaction.add(primes, "primes").commit(); } If our Activity has been restarted, it will need to re-display the progress dialog when a progress update callback is received, so we check and show it, if necessary, before updating the progress bar: public void onProgressUpdate(Integer... progress) { if (dialog == null) prepareProgressDialog(); progress.setProgress(progress[0]); } Finally, Activity will need to implement the onPostExecute and onCancelled callbacks defined by AsyncListener. Both methods will update the resultView as in the previous examples, then do a little cleanup—dismissing the dialog and removing Fragment as its work is now done: public void onPostExecute(BigInteger result) { resultView.setText(result.toString()); cleanUp(); } public void onCancelled(BigInteger result) { resultView.setText("cancelled at " + result); cleanUp(); } private void cleanUp() { dialog.dismiss(); dialog = null; FragmentManager fm = getSupportFragmentManager(); Fragment primes = fm.findFragmentByTag("primes"); fm.beginTransaction().remove(primes).commit(); } Summary In this article, we've taken a look at AsyncTask and how to use it to write responsive applications that perform operations without blocking the main thread. Resources for Article: Further resources on this subject: Android Native Application API [Article] So, what is Spring for Android? [Article] Creating Dynamic UI with Android Fragments [Article]
Read more
  • 0
  • 0
  • 12112

article-image-drawing-and-drawables-android-canvas
Packt
21 Nov 2013
8 min read
Save for later

Drawing and Drawables in Android Canvas

Packt
21 Nov 2013
8 min read
In this article by Mir Nauman Tahir, the author of the book Learning Android Canvas, our goal is to learn about the following: Drawing on a Canvas Drawing on a View Drawing on a SurfaceView Drawables Drawables from resource images Drawables from resource XML Shape Drawables (For more resources related to this topic, see here.) Android provides us with 2D drawing APIs that enable us to draw our custom drawing on the Canvas. When working with 2D drawings, we will either draw on view or directly on the surface or Canvas. Using View for our graphics, the drawing is handled by the system's normal View hierarchy drawing process. We only define our graphics to be inserted in the View; the rest is done automatically by the system. While using the method to draw directly on the Canvas, we have to manually call the suitable drawing Canvas methods such as onDraw() or createBitmap(). This method requires more efforts and coding and is a bit more complicated, but we have everything in control such as the animation and everything else like being in control of the size and location of the drawing and the colors and the ability to move the drawing from its current location to another location through code. The implementation of the onDraw() method can be seen in the drawing on the view section and the code for createBitmap() is shown in the Drawing on a Canvas section. We will use the drawing on the View method if we are dealing with static graphics–static graphics do not change dynamically during the execution of the application–or if we are dealing with graphics that are not resource hungry as we don't wish to put our application performance at stake. Drawing on a View can be used for designing eye-catching simple applications with static graphics and simple functionality–simple attractive backgrounds and buttons. It's perfectly okay to draw on View using the main UI thread as these graphics are not a threat to the overall performance of our application. The drawing on a Canvas method should be used when working with heavy graphics that change dynamically like those in games. In this scenario, the Canvas will continuously redraw itself to keep the graphics updated. We can draw on a Canvas using the main UI thread, but when working with heavy, resource-hungry, dynamically changing graphics, the application will continuously redraw itself. It is better to use a separate thread to draw these graphics. Keeping such graphics on the main UI thread will not make them go into the non-responding mode, and after working so hard we certainly won't like this. So this choice should be made very carefully. Drawing on a Canvas A Canvas is an interface, a medium that enables us to actually access the surface, which we will use to draw our graphics. The Canvas contains all the necessary drawing methods needed to draw our graphics. The actual internal mechanism of drawing on a Canvas is that, whenever anything needs to be drawn on the Canvas, it's actually drawn on an underlying blank bitmap image. By default, this bitmap is automatically provided for us. But if we want to use a new Canvas, then we need to create a new bitmap image and then a new Canvas object while providing the already created bitmap to the constructor of the Canvas class. A sample code is explained as follows. Initially, the bitmap is drawn but not on the screen; it's actually drawn in the background on an internal Canvas. But to bring it to the front, we need to create a new Canvas object and provide the already created bitmap to it to be painted on the screen. Bitmap ourNewBitmap = Bitmap.CreateBitmap(100,100,Bitmap.Config.ARGB_8888); Canvas ourNewCanvas = new Canvas(ourNewBitmap); Drawing on a View If our application does not require heavy system resources or fast frame rates, we should use View.onDraw(). The benefit in this case is that the system will automatically give the Canvas its underlying bitmap as well. All we need is to make our drawing calls and be done with our drawings. We will create our class by extending it from the View class and will define the onDraw() method in it. The onDraw() method is where we will define whatever we want to draw on our Canvas. The Android framework will call the onDraw() method to ask our View to draw itself. The onDraw() method will be called by the Android framework on a need basis; for example, whenever our application wants to draw itself, this method will be called. We have to call the invalidate() method whenever we want our view to redraw itself. This means that, whenever we want our application's view to be redrawn, we will call the invalidate() method and the Android framework will call the onDraw() method for us. Let's say we want to draw a line, then the code would be something like this: class DrawView extends View { Paint paint = new Paint(); public DrawView(Context context) { super(context); paint.setColor(Color.BLUE); } @Override public void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawLine(10, 10, 90, 10, paint); } } Inside the onDraw() method, we will use all kinds of facilities that are provided by the Canvas class such as the different drawing methods made available by the Canvas class. We can also use drawing methods from other classes as well. The Android framework will draw a bitmap on the Canvas for us once our onDraw() method is complete with all our desired functionality. If we are using the main UI thread, we will call the invalidate() method, but if we are using another thread, then we will call the postInvalidate() method. Drawing on a SurfaceView The View class provides a subclass SurfaceView that provides a dedicated drawing surface within the hierarchy of the View. The goal is to draw using a secondary thread so that the application won't wait for the resources to be free and ready to redraw. The secondary thread has access to the SurfaceView object that has the ability to draw on its own Canvas with its own redraw frequency. We will start by creating a class that will extend the SurfaceView class. We should implement an interface SurfaceHolder.Callback. This interface is important in the sense that it will provide us with the information when a surface is created, modified, or destroyed. When we have timely information about the creation, change, or destruction of a surface, we can make a better decision on when to start drawing and when to stop. The secondary thread class that will perform all the drawing on our Canvas can also be defined in the SurfaceView class. To get information, the Surface object should be handled through SurfaceHolder and not directly. To do this, we will get the Holder by calling the getHolder() method when the SurfaceView is initialized. We will then tell the SurfaceHolder object that we want to receive all the callbacks; to do this, we will call addCallBacks(). After this, we will override all the methods inside the SurfaceView class to get our job done according to our functionality. The next step is to draw the surface's Canvas from inside the second thread; to do this, we will pass our SurfaceHandler object to the thread object and will get the Canvas using the lockCanvas() method. This will get the Canvas for us and will lock it for the drawing from the current thread only. We need to do this because we don't want an open Canvas that can be drawn by another thread; if this is the situation, it will disturb all our graphics and drawings on the Canvas. When we are done with drawing our graphics on the Canvas, we will unlock the Canvas by calling the unlockCanvasAndPost() method and will pass our Canvas object. To have a successful drawing, we will need repeated redraws; so we will repeat this locking and unlocking as needed and the surface will draw the Canvas. To have a uniform and smooth graphic animation, we need to have the previous state of the Canvas; so we will retrieve the Canvas from the SurfaceHolder object every time and the whole surface should be redrawn each time. If we don't do so, for instance, not painting the whole surface, the drawing from the previous Canvas will persist and that will destroy the whole look of our graphic-intense application. A sample code would be the following: class OurGameView extends SurfaceView implements SurfaceHolder.Callback { Thread thread = null; SurfaceHolder surfaceHolder; volatile boolean running = false; public void OurGameView (Context context) { super(context); surfaceHolder = getHolder(); } public void onResumeOurGameView (){ running = true; thread = new Thread(this); thread.start(); } public void onPauseOurGameView(){ boolean retry = true; running = false; while(retry){ thread.join(); retry = false; } public void run() { while(running){ if(surfaceHolder.getSurface().isValid()){ Canvas canvas = surfaceHolder.lockCanvas(); //... actual drawing on canvas surfaceHolder.unlockCanvasAndPost(canvas); } } } }
Read more
  • 0
  • 0
  • 11690

article-image-developing-apps-google-speech-apis
Packt
21 Nov 2013
6 min read
Save for later

Developing apps with the Google Speech APIs

Packt
21 Nov 2013
6 min read
(For more resources related to this topic, see here.) Speech technology has come of age. If you own a smartphone or tablet you can perform many tasks on your device using voice. For example, you can send a text message, update your calendar, set an alarm, and do many other things with a single spoken command that would take multiple steps to complete using traditional methods such as tapping and selecting. You can also ask the sorts of queries that you would previously have typed into your Google search box and get a spoken response. For those who wish to develop their own speech-based apps, Google provides APIs for the basic technologies of text-to-speech synthesis (TTS) and automated speech recognition (ASR). Using these APIs developers can create useful interactive voice applications. This article provides a brief overview of the Google APIs and then goes on to show some examples of voice-based apps built around the APIs. Using the Google text-to-speech synthesis API TTS has been available on Android devices since Android 1.6 (API Level 4). The components of the Google TTS API (package android.speech.tts) are documented at http://developer.android.com/reference/android/speech/tts/package-summary.html. Interfaces and classes are listed here and further details can be obtained by clicking on these. Starting the TTS engine involves creating an instance of the TextToSpeech class along with the method that will be executed when the TTS engine is initialized. Checking that TTS has been initialized is done through an interface called OnInitListener. If TTS initialization is complete, the method onInit is invoked. If TTS has been initialized correctly, the speak method is invoked to speak out some words: TextToSpeech tts = new TextToSpeech(this, new OnInitListener(){ public void onInit(int status) { if (status == TextToSpeech.SUCCESS) speak(“Hello world”, TextToSpeech.QUEUE_ADD, null); } } Due to limited storage on some devices, not all languages that are supported may actually be installed on a particular device so it is important to check if a particular language is available before creating the TextToSpeech object. This way, it is possible to download and install the required language-specific resource files if necessary. This is done by sending an Intent with the action ACTION_CHECK_TTS_DATA, which is part of the TextToSpeech.Engine class: Intent intent = new In-tent(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA); startActivityForResult(intent,TTS_DATA_CHECK); If the language data has been correctly installed, the onActivityResult handler will receive a CHECK_VOICE_DATA_PASS. If the data is not available, the action ACTION_INSTALL_TTS_DATA will be executed: Intent installData = new Intent (Engine. ACTION_INSTALL_TTS_DATA); startActivity(installData); The next figure shows an example of an app using the TTS API. A potential use-case for this type of app is when the user accesses some text on the Web - for example, a news item, email, or a sports report. This is useful if the user’s eyes and hands are busy, or if there are problems reading the text on the screen. In this example, the app retrieves some text and the user presses the Speak button to hear it. A Stop button is provided in case the user does not wish to hear all of the text. Using the Google speech recognition API The components of the Google Speech API (package android.speech) are documented at http://developer.android.com/reference/android/speech/package-summary.html. Interfaces and classes are listed and further details can be obtained by clicking on these. There are two ways in which speech recognition can be carried out on an Android Device: based solely on a RecognizerIntent, or by creating an instance of SpeechRecognizer. The following code shows how to start an activity to recognize speech using the first approach: Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); // Specify language model intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, languageModel); // Specify how many results to receive. Results listed in order of confidence intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, numberRecoResults); // Start listening startActivityForResult(intent, ASR_CODE); The app shown below illustrates the following: The user selects the parameters for speech recognition. The user presses a button and says some words. The words recognized are displayed in a list along with their confidence scores. Multilingual apps It is important to be able to develop apps in languages other than English. The TTS and ASR engines can be configured to a wide range of languages. However, we cannot expect that all languages will be available or that they are supported on a particular device. Thus, before selecting a language it is necessary to check whether it is one of the supported languages, and if not, to set the currently preferred language. In order to do this, a RecognizerIntent.ACTION_GET_LANGUAGE_DETAILS ordered broadcast is sent that returns a Bundle from which the information about the preferred language (RecognizerIntent.EXTRA_LANGUAGE_PREFERENCE) and the list of supported languages (RecognizerIntent.EXTRA_SUPPORTED_LANGUAGES) can be extracted. For speech recognition this introduces a new parameter for the intent in which the language is specified that will be used for recognition, as shown in the following code line: intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); As shown in the next figure, the user is asked for a language and then the app recognizes what the user says and plays back the best recognition result in the language selected. Creating a Virtual Personal Assistant (VPA) Many voice-based apps need to do more than simply speak and understand speech. For example, a VPA also needs the ability to engage in dialog with the user and to perform operations such as connecting to web services and activating device functions. One way to enable these additional capabilities is to make use of chatbot technology (see, for example, the Pandorabots web service: http://www.pandorabots.com/). The following figure shows two VPAs, Jack and Derek, that have been developed in this way. Jack is a general-purpose VPA, while Derek is a specialized VPA that can answer questions about Type 2 diabetes, such as symptoms, causes, treatment, risks to children, and complications. Summary The Google Speech APIs can be used in countless ways to develop interesting and useful voice-based apps. This article has shown some examples. By building on these you will be able to bring the power of voice to your Android apps, making them smarter and more intuitive, and boosting your users' mobile experience. Resources for Article: Further resources on this subject: Introducing an Android platform [Article] Building Android (Must know) [Article] Top 5 Must-have Android Applications [Article]
Read more
  • 0
  • 0
  • 11558

article-image-so-what-spring-android
Packt
20 Feb 2013
3 min read
Save for later

So, what is Spring for Android?

Packt
20 Feb 2013
3 min read
(For more resources related to this topic, see here.) RestTemplate The RestTemplate module is a port of the Java-based REST client RestTemplate, which initially appeared in 2009 in Spring for MVC. Like the other Spring template counterparts (JdbcTemplate, JmsTemplate, and so on), its aim is to bring to Java developers (and thus Android developers) a high-level abstraction of lower-level Java API; in this case, it eases the development of HTTP clients. In its Android version, RestTemplate relies on the core Java HTTP facilities (HttpURLConnection) or the Apache HTTP Client. According to the Android device version you use to run your app, RestTemplate for Android can pick the most appropriate one for you. This is according to Android developers' recommendations. See http://android-developers.blogspot.ca/2011/09/androids-http-clients.html. This blog post explains why in certain cases Apache HTTP Client is preferred over HttpURLConnection. RestTemplate for Android also supports gzip compression and different message converters to convert your Java objects from and to JSON, XML, and so on. Auth/Spring Social The goal of the Spring Android Auth module is to let an Android app gain authorization to a web service provider using OAuth (Version 1 or 2). OAuth is probably the most popular authorization protocol (and it is worth mentioning that, it is an open standard) and is currently used by Facebook, Twitter, Google apps (and many others) to let third-party applications access users account. Spring for Android Auth module is based on several Spring libraries because it needs to securely (with cryptography) persist (via JDBC) a token obtained via HTTP; here is a list of the needed libraries for OAuth: Spring Security Crypto: To encrypt the token Spring Android OAuth: This extends Spring Security Crypto adding a dedicated encryptor for Android, and SQLite based persistence provider Spring Android Rest Template: To interact with the HTTP services Spring Social Core: The OAuth workflow abstraction While performing the OAuth workflow, we will also need the browser to take the user to the service provider authentication page, for example, the following is the Twitter OAuth authentication dialog: What Spring for Android is not SpringSource (the company behind Spring for Android) is very famous among Java developers. Their most popular product is the Spring Framework for Java which includes a dependency injection framework (also called an inversion of control framework). Spring for Android does not bring inversion of control to the Android platform. In its very first release (1.0.0.M1), Spring for Android brought a common logging facade for Android; the authors removed it in the next version. Summary In this article, we have learned that Spring for Android helps in easy development of Android applications. We learned the details about the important modules present in it and its functions. We also learnt about dependency injection framework in short and that Spring for Android does not bring inversion of control to the Android platform. Resources for Article : Further resources on this subject: Top 5 Must-have Android Applications [Article] Creating, Compiling, and Deploying Native Projects from the Android NDK [Article] Manifest Assurance: Security and Android Permissions for Flash [Article]
Read more
  • 0
  • 0
  • 10857

article-image-get-your-apps-ready-android-n
Packt
18 Mar 2016
9 min read
Save for later

Get your Apps Ready for Android N

Packt
18 Mar 2016
9 min read
It seems likely that Android N will get its first proper outing in May, at this year's Google I/O conference, but there's no need to wait until then to start developing for the next major release of the Android platform. Thanks to Google's decision to release preview versions early you can start getting your apps ready for Android N today. In this article by Jessica Thornsby, author of the book Android UI Design, going to look at the major new UI features that you can start experimenting with right now. And since you'll need something to develop your Android N-ready apps in, we're also going to look at Android Studio 2.1, which is currently the recommended development environment for Android N. (For more resources related to this topic, see here.) Multi-window mode Beginning with Android N, the Android operating system will give users the option to display more than one app at a time, in a split-screen environment known as multi-window mode. Multi-window paves the way for some serious multi-app multi-tasking, allowing users to perform tasks such as replying to an email without abandoning the video they were halfway through watching on YouTube, and reading articles in one half of the screen while jotting down notes in Google Keep on the other. When two activities are sharing the screen, users can even drag data from one activity and drop it into another activity directly, for example dragging a restaurant's address from a website and dropping it into Google Maps. Android N users can switch to multi-window mode either by: Making sure one of the apps they want to view in multi-window mode is visible onscreen, then tapping their device's Recent Apps softkey (that's the square softkey). The screen will split in half, with one side displaying the current activity and the other displaying the Recent Apps carousel. The user can then select the secondary app they want to view, and it'll fill the remaining half of the screen. Navigating to the home screen, and then pressing the Recent Apps softkey to open the Recent Apps carousel. The user can then drag one of these apps to the edge of the screen, and it'll open in multi-window mode. The user can then repeat this process for the second activity. If your app targets Android N or higher, the Android operating system assumes that your app supports multi-window mode unless you explicitly state otherwise. To prevent users from displaying your app in multi-window mode, you'll need to add android:resizeableActivity="false" to the <activity> or <application> section of your project's Manifest file. If your app does support multi-window mode, you may want to prevent users from shrinking your app's UI beyond a specified size, using the android:minimalSize attribute. If the user attempts to resize your app so it's smaller than the android:minimalSize value, the system will crop your UI instead of shrinking it. Direct reply notifications Google are adding a few new features to notifications in Android N, including an inline reply action button that allows users to reply to notifications directly from the notification UI.   This is particularly useful for messaging apps, as it means users can reply to messages without even having to launch the messaging application. You may have already encountered direct reply notifications in Google Hangouts. To create a notification that supports direct reply, you need to create an instance of RemoteInput.Builder and then add it to your notification action. The following code adds a RemoteInput to a Notification.Action, and creates a Quick Reply key. When the user triggers the action, the notification prompts the user to input their response: private static final String KEY_QUICK_REPLY = "key_quick_reply"; String replyLabel = getResources().getString(R.string.reply_label); RemoteInput remoteInput = new RemoteInput.Builder(KEY_QUICK_REPLY) .setLabel(replyLabel) .build(); To retrieve the user's input from the notification interface, you need to call: getResultsFromIntent(Intent) and pass the notification action's intent as the input parameter: Bundle remoteInput = RemoteInput.getResultsFromIntent(intent); //This method returns a Bundle that contains the text response// if (remoteInput != null) { return remoteInput.getCharSequence(KEY_QUICK_REPLY); //Query the bundle using the result key, which is provided to the RemoteInput.Builder constructor// Bundled notifications Don't you just hate it when you connect to the World Wide Web first thing in the morning, and Gmail bombards you with multiple new message notifications, but doesn't give you anymore information about the individual emails? Not particularly helpful! When you receive a notification that consists of multiple items, the only thing you can really do is launch the app in question and take a closer look at the events that make up this grouped notification. Android N overcomes this drawback, by letting you group multiple notifications from the same app into a single, bundled notification via a new notification style: bundled notifications. A bundled notification consists of a parent notification that displays summary information for that group, plus individual notification items. If the user wants to see more information about one or more individual items, they can unfurl the bundled notification into separate notifications by swiping down with two fingers. The user can then act on each mini-notification individually, for example they might choose to dismiss the first three notifications about spam emails, but open the forth e-mail. To group notifications, you need to call setGroup() for each notification you want to add to the same notification stack, and then assign these notifications the same key. final static String GROUP_KEY_MESSAGES = "group_key_messages"; Notification notif = new NotificationCompat.Builder(mContext) .setContentTitle("New SMS from " + sender1) .setContentText(subject1) .setSmallIcon(R.drawable.new_message) .setGroup(GROUP_KEY_MESSAGES) .build(); Then when you create another notification that belongs to this stack, you just need to assign it the same group key. Notification notif2 = new NotificationCompat.Builder(mContext) .setContentTitle("New SMS from " + sender1) .setContentText(subject2) .setGroup(GROUP_KEY_MESSAGES) .build(); The second Android N developer preview introduced an Android-specific implementation of the Vulkan API. Vulkan is a cross-platform, 3D rendering API for providing high-quality, real-time 3D graphics. For draw-call heavy applications, Vulkan also promises to deliver a significant performance boost, thanks to a threading-friendly design and a reduction of CPU overhead. You can try Vulkan for yourself on devices running Developer Preview 2, or learn more about Vulkan at the official Android docs (https://developer.android.com/ndk/guides/graphics/index.html?utm_campaign=android_launch_npreview2_041316&utm_source=anddev&utm_medium=blog). Android N Support in Android Studio 2.1 The two Developer Previews aren't the only important releases for developers who want to get their apps ready for Android N. Google also recently released a stable version of Android Studio 2.1, which is the recommended IDE for developing Android N apps. Crucially, with the release of Android Studio 2.1 the emulator can now run the N Developer Preview Emulator System Images, so you can start testing your apps against Android N. Particularly with features like multi-window mode, it's important to test your apps across multiple screen sizes and configurations, and creating various Android N Android Virtual Devices (AVDs) is the quickest and easiest ways to do this. Android 2.1 also adds the ability to use the new Jack compiler (Java Android Compiler Kit), which compiles Java source code into Android dex bytecode. Jack is particularly important as it opens the door to using Java 8 language features in your Android N projects, without having to resort to additional tools or resources. Although not Android N-specific, Android 2.1 makes some improvements to the Instant Run feature, which should result in faster editing and deploy builds for all your Android projects. Previously, one small change in the Java code would cause all Java sources in the module to be recompiled. Instant Run aims to reduce compilation time by analyzing the changes you've made and determining how it can deploy them in the fastest way possible. This is instead of Android Studio automatically going through the lengthy process of recompiling the code, converting it to dex format, generating an APK and installing it on the connected device or emulator every time you make even a small change to your project. To start using Instant Run, select Android Studio from the toolbar followed by Preferences…. In the window that appears, select Build, Execution, Deployment from the side-menu and select Instant Run. Uncheck the box next to Restart activity on code changes. Instant Run is supported only when you deploy a debug build for Android 4.0 or higher. You'll also need to be using Android Plugin for Gradle version 2.0 or higher. Instant Run isn't currently compatible with the Jack toolchain. To use Instant Run, deploy your app as normal. Then if you make some changes to your project you'll notice that a yellow thunderbolt icon appears within the Run icon, indicating that Android Studio will push updates via Instant Run when you click this button. You can update to the latest version of Android Studio by launching the IDE and then selecting Android Studio from the toolbar, followed by Check for Updates…. Summary In this article, we looked at the major new UI features currently available in the Android N Developer Preview. We also looked at the Android Studio 2.1 features that are particularly useful for developing and testing apps that target the upcoming Android N release. Although we should expect some pretty dramatic changes between these early previews and the final release of Android N, taking the time to explore these features now means you'll be in a better position to update your apps when Android N is finally released. Resources for Article: Further resources on this subject: Drawing and Drawables In Android Canvas [article] Behavior-Driven Development With Selenium Webdriver [article] Development of Iphone Applications [article]
Read more
  • 0
  • 0
  • 10786

article-image-prototype-pattern
Packt
27 Dec 2016
5 min read
Save for later

The prototype pattern

Packt
27 Dec 2016
5 min read
In this article by Kyle Mew, author of the book Android Design Patterns and Best Practices, we will discuss how the prototype design pattern performs similar tasks to other creational patterns, such as builders and factories, but it takes a very different approach. Rather than relying heavily on a number of hardcoded subclasses, the prototype, as its name suggests, makes copies of an original, vastly reducing the number of subclasses required and preventing any lengthy creation processes. (For more resources related to this topic, see here.) Setting up a prototype The prototype is most useful when the creation of an instance is expensive in some way. This could be the loading of a large file, a detailed cross-examination of a database, or some other computationally expensive operation. Furthermore, it allows us to decouple cloned objects from their originals, allowing us to make modifications without having to reinstantiate each time. In the following example, we will demonstrate this using functions that take considerable time to calculate when first created, the nth prime number and the nth Fibonacci number. Viewed diagrammatically, our prototype will look like this: We will not need the prototype pattern in our main app as there are very few expensive creations as such. However, it is vitally important in many situations and should not be neglected. Follow the given steps to apply a prototype pattern: We will start with the following abstract class: public abstract class Sequence implements Cloneable { protected long result; private String id; public long getResult() { return result; } public String getId() { return id; } public void setId(String id) { this.id = id; } public Object clone() { Object clone = null; try { clone = super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return clone; } } Next, add this cloneable concrete class, as shown: // Calculates the 10,000th prime number public class Prime extends Sequence { public Prime() { result = nthPrime(10000); } public static int nthPrime(int n) { int i, count; for (i = 2, count = 0; count < n; ++i) { if (isPrime(i)) { ++count; } } return i - 1; } // Test for prime number private static boolean isPrime(int n) { for (int i = 2; i < n; ++i) { if (n % i == 0) { return false; } } return true; } } Add another Sequence class, like so: for the Fibonacci numbers, like so: // Calculates the 100th Fibonacci number public class Fibonacci extends Sequence { public Fibonacci() { result = nthFib(100); } private static long nthFib(int n) { long f = 0; long g = 1; for (int i = 1; i <= n; i++) { f = f + g; g = f - g; } return f; } } Next, create the cache class, as follows: public class SequenceCache { private static Hashtable<String, Sequence> sequenceHashtable = new Hashtable<String, Sequence>(); public static Sequence getSequence(String sequenceId) { Sequence cachedSequence = sequenceHashtable.get(sequenceId); return (Sequence) cachedSequence.clone(); } public static void loadCache() { Prime prime = new Prime(); prime.setId("1"); sequenceHashtable.put(prime.getId(), prime); Fibonacci fib = new Fibonacci(); fib.setId("2"); sequenceHashtable.put(fib.getId(), fib); } } Add three TextViews to your layout, and then, add the code to your Main Activity's onCreate() method. Add the following lines to the client code: // Load the cache once only SequenceCache.loadCache(); // Lengthy calculation and display of prime result Sequence prime = (Sequence) SequenceCache.getSequence("1"); primeText.setText(new StringBuilder() .append(getString(R.string.prime_text)) .append(prime.getResult()) .toString()); // Lengthy calculation and display of Fibonacci result SSequence fib = (Sequence) SequenceCache.getSequence("2"); fibText.setText(new StringBuilder() .append(getString(R.string.fib_text)) .append(fib.getResult()) .toString()); As you can see, the preceding code creates the pattern but does not demonstrate it. Once loaded, the cache can create instant copies of our previously expensive output. Furthermore, we can modify the copy, making the prototype very useful when we have a complex object and want to modify just one or two properties. Applying the prototype Consider a detailed user profile similar to what you might find on a social media site. Users modify details such as images and text, but the overall structure is the same for all profiles, making it an ideal candidate for a prototype pattern. To put this principle into practice, include the following code in your client source code: // Create a clone of already constructed object Sequence clone = (Fibonacci) new Fibonacci().clone(); // Modify the result long result = clone.getResult() / 2; // Display the result quickly cloneText.setText(new StringBuilder() .append(getString(R.string.clone_text)) .append(result) .toString()); The prototype is a very useful pattern in many occasions, where we have expensive objects to create or when we face a proliferation of subclasses. Although this is not the only pattern that helps reduce excessive sub classing, it leads us on to another design pattern, decorator. Summary In this article we explored the vital pattern, the prototype pattern and saw how vital it can be whenever we have large files or slow processes to contend with. Resources for Article: Further resources on this subject: Why we need Design Patterns? [article] Understanding Material Design [article] Asynchronous Control Flow Patterns with ES2015 and beyond [article]
Read more
  • 0
  • 0
  • 10717
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at $19.99/month. Cancel anytime
article-image-building-your-first-android-wear-application
Packt
18 Feb 2016
18 min read
Save for later

Building your first Android Wear Application

Packt
18 Feb 2016
18 min read
One of the most exciting new directions that Android has gone in recently, is the extension of the platform from phones and tablets to televisions, car dashboards and wearables such as watches. These new devices allow us to provide added functionality to our existing apps, as well as creating wholly original apps designed specifically for these new environments. This article is really concerned with explaining the idiosyncrasies of each platform and the guidelines Google is keen for us to follow. This is particularly vital when it comes to developing apps that people will use when driving, as safety has to be of prime importance. There are also certain technical issues that need to be addressed when developing wearable apps, such as the pairing of the device with a handset and the entirely different UI and methods of use. In this article, you will: Create wearable AVDs Connect a wearable emulator to a handset with adb commands Connect a wearable emulator to a handset emulator Create a project with both mobile and wearable modules Use the Wearable UI Library Create shape-aware layouts Create and customize cards for wearables Understand wearable design principles (For more resources related to this topic, see here.) Android Wear Creating or adapting apps for wearables is probably the most complicated factors and requires a little more setting up than the other projects. However, wearables often give us access to one of the more fun new sensors, the heart rate monitor. In seeing how this works, we also get to see, how to manage sensors in general. Do not worry if you do not have access to an Android wearable device, as we will be constructing AVDs. You will ideally have an actual Android 5 handset, if you wish to pair it with the AVD. If you do not, it is still possible to work with two emulators but it is a little more complex to set up. Bearing this in mind, we can now prepare our first wearable app. Constructing and connecting to a wearable AVD It is perfectly possible to develop and test wearable apps on the emulator alone, but if we want to test all wearable features, we will need to pair it with a phone or a tablet. The next exercise assumes that you have an actual device. If you do not, still complete tasks 1 through 4 and we will cover how the rest can be achieved with an emulator a little later on. Open Android Studio. You do not need to start a project at this point. Start the SDK Manager and ensure you have the relevant packages installed. Open the AVD Manager. Create two new Android Wear AVDs, one round and one square, like so: Ensure USB Debugging is selected on your handset. Install the Android Wear app from the Play Store at this URL: https://play.google.com/store/apps/details?id=com.google.android.wearable.app. Connect it to your computer and start one of the AVDs we just created. Locate and open the folder containing the adb.exe file. It will probably be something like userAppDataLocalAndroidsdkplatform-tools. Using Shift + right-click, select Open command window here. In the command window, issue the following command: adb -d forward tcp:5601 tcp:5601 Launch the companion app and follow the instructions to pair the two devices. Being able to connect a real-world device to an AVD is a great way to develop form factors without having to own the devices. The wearable companion app simplifies the process of connecting the two. If you have had the emulator running for any length of time, you will have noticed that many actions, such as notifications, are sent to the wearable automatically. This means that very often our apps will link seamlessly with a wearable device, without us having to include code to pre-empt this. The adb.exe (Android Debug Bridge) is a vital part of our development toolkit. Most of the time, the Android Studio manages it for us. However, it is useful to know that it is there and a little about how to interact with it. We used it here to manually open a port between our wearable AVD and our handset. There are many adb commands that can be issued from the command prompt and perhaps the most useful is adb devices, which lists all currently debuggable devices and emulators, and is very handy when things are not working, to see if an emulator needs restarting. Switching the ADB off and on can be achieved using adb kill-server and adb start-server respectively. Using adb help will list all available commands. The port forwarding command we used in Step 10, needs to be issued every time the phone is disconnected from the computer. Without writing any code as such, we have already seen some of the features that are built into an Android Wear device and the way that the Wear UI differs from most other Android devices. Even if you usually develop with the latest Android hardware, it is often still a good idea to use an emulator, especially for testing the latest SDK updates and pre-releases. If you do not have a real device, then the next, small section will show you how to connect your wearable AVD to a handset AVD. Connecting a wearable AVD with another emulator Pairing two emulators is very similar to pairing with a real device. The main difference is the way we install the companion app without access to the Play Store. Follow these steps to see how it is done: Start up, an AVD. This will need to be targeting Google APIs as seen here: Download the com.google.android.wearable.app-2.apk. There are many places online where it can be found with a simple search, I used www.file-upload.net/download. Place the file in your sdk/platform-tools directory. Shift + right-click in this folder and select Open command window here. Enter the following command: adb install com.google.android.wearable.app-2.apk. Start your wearable AVD. Enter adb devices into the command prompt, making sure that both emulators are visible with an output similar to this: List of devices attached emulator-5554 device emulator-5555 device Enter adb telnet localhost 5554 at the command prompt, where 5554 is the phone emulator. Next, enter adb redir add tcp:5601:5601. You can now use the Wear app on the handheld AVD to connect to the watch. As we've just seen, setting up a Wear project takes a little longer than some of the other exercises we have performed. Once set up though, the process is very similar to that of developing for other form factors, and something we can now get on with. Creating a wearable project All of the apps that we have developed so far, have required just a single module, and this makes sense as we have only been building for single devices. In this next step, we will be developing across two devices and so will need two modules. This is very simple to do, as you will see in these next steps. Start a new project in the Android Studio and call it something like Wearable App. On the Target Android Devices screen, select both Phone and Tablet and Wear, like so: You will be asked to add two Activities. Select Blank Activity for the Mobile Activity and Blank Wear Activity for Wear. Everything else can be left as it is. Run the app on both round and square virtual devices. The first thing you will have noticed is the two modules, mobile and wear. The first is the same as we have seen many times, but there are a few subtle differences with the wear module and it is worth taking a little look at. The most important difference is the WatchViewStub class. The way it is used can be seen in the activity_main.xml and MainActivity.java files of the wear module. This frame layout extension is designed specifically for wearables and detects the shape of the device, so that the appropriate layout is inflated. Utilizing the WatchViewStub is not quite as straightforward, as one might imagine, as the appropriate layout is only inflated after the WatchViewStub has done its thing. This means that, to access any views within the layout, we need to employ a special listener that is called once the layout has been inflated. How this OnLayoutInflatedListener() works can be seen by opening the MainActivity.java file in the wear module and examining the onCreate() method, which will look like this: @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub); stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() { @Override public void onLayoutInflated(WatchViewStub stub) { mTextView = (TextView) stub.findViewById(R.id.text); } }); } Other than the way that wearable apps and devices are set up for developing, the other significant difference is the UI. The widgets and layouts that we use for phones and tablets are not suitable, in most cases, for the diminished size of a watch screen. Android provides a whole new set of UI components, that we can use and this is what we will look at next. Designing a UI for wearables As well as having to consider the small size of wearable when designing layouts, we also have the issue of shape. Designing for a round screen brings its own challenges, but fortunately the Wearable UI Library makes this very simple. As well as the WatchViewStub, that we encountered in the previous section that inflates the correct layout, there is also a way to design a single layout that inflates in such a way, that it is suitable for both square and round screens. Designing the layout The project setup wizard included this library for us automatically in the build.gradle (Module: wear) file as a dependency: compile 'com.google.android.support:wearable:1.1.0' The following steps demonstrate how to create a shape-aware layout with a BoxInsetLayout: Open the project we created in the last section. You will need three images that must be placed in the drawable folder of the wear module: one called background_image of around 320x320 px and two of around 50x50 px, called right_icon and left_icon. Open the activity_main.xml file in the wear module. Replace its content with the following code: <android.support.wearable.view.BoxInsetLayout android_background="@drawable/background_image" android_layout_height="match_parent" android_layout_width="match_parent" android_padding="15dp"> </android.support.wearable.view.BoxInsetLayout> Inside the BoxInsetLayout, add the following FrameLayout: <FrameLayout android_id="@+id/wearable_layout" android_layout_width="match_parent" android_layout_height="match_parent" android_padding="5dp" app_layout_box="all"> </FrameLayout> Inside this, add these three views: <TextView android_gravity="center" android_layout_height="wrap_content" android_layout_width="match_parent" android_text="Weather warning" android_textColor="@color/black" /> <ImageView android_layout_gravity="bottom|left" android_layout_height="60dp" android_layout_width="60dp" android_src="@drawable/left_icon" /> <ImageView android_layout_gravity="bottom|right" android_layout_height="60dp" android_layout_width="60dp" android_src="@drawable/right_icon" /> Open the MainActivity.java file in the wear module. In the onCreate() method, delete all lines after the line setContentView(R.layout.activity_main);. Now, run the app on both square and round emulators. As we can see, the BoxInsetLayout does a fine job of inflating our layout regardless of screen shape. How it works is very simple. The BoxInsetLayout creates a square region, that is as large as can fit inside the circle of a round screen. This is set with the app:layout_box="all" instruction, which can also be used for positioning components, as we will see in a minute. We have also set the padding of the BoxInsetLayout to 15 dp and that of the FrameLayout to 5 dp. This has the effect of a margin of 5 dp on round screens and 15 dp on square ones. Whether you use the WatchViewStub and create separate layouts for each screen shape or BoxInsetLayout and just one layout file depends entirely on your preference and the purpose and design of your app. Whichever method you choose, you will no doubt want to add Material Design elements to your wearable app, the most common and versatile of these being the card. In the following section, we will explore the two ways that we can do this, the CardScrollView and the CardFragment. Adding cards The CardFragment class provides a default card view, providing two text views and an image. It is beautifully simple to set up, has all the Material Design features such as rounded corners and a shadow, and is suitable for nearly all purposes. It can be customized, as we will see, although the CardScrollView is often a better option. First, let us see, how to implement a default card for wearables: Open the activity_main.xml file in the wear module of the current project. Delete or comment out the the text view and two image views. Open the MainActivity.java file in the wear module. In the onCreate() method, add the following code: FragmentManager fragmentManager = getFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); CardFragment cardFragment = CardFragment.create("Short title", "with a longer description"); fragmentTransaction.add(R.id.wearable_layout, cardFragment); fragmentTransaction.commit(); Run the app on one or other of the wearable emulators to see how the default card looks. The way we created the CardFragment itself, is also very straightforward. We used two string parameters here, but there is a third, drawable parameter and if the line is changed to CardFragment cardFragment = CardFragment.create("TITLE", "with description and drawable", R.drawable.left_icon); then we will get the following output: This default implementation for cards on wearable is fine for most purposes and it can be customized by overriding its onCreateContentView() method. However, the CardScrollView is a very handy alternative, and this is what we will look at next. Customizing cards The CardScrollView is defined from within our layout and furthermore it detects screen shape and adjusts the margins to suit each shape. To see how this is done, follow these steps: Open the activity_main.xml file in the wear module. Delete or comment out every element, except the root BoxInsetLayout. Place the following CardScrollView inside the BoxInsetLayout: <android.support.wearable.view.CardScrollView android_id="@+id/card_scroll_view" android_layout_height="match_parent" android_layout_width="match_parent" app_layout_box="bottom"> </android.support.wearable.view.CardScrollView> Inside this, add this CardFrame: <android.support.wearable.view.CardFrame android_layout_width="match_parent" android_layout_height="wrap_content"> </android.support.wearable.view.CardFrame> Inside the CardFrame, add a LinearLayout. Add some views to this, so that the preview resembles the layout here: Open the MainActivity.java file. Replace the code we added to the onCreate() method with this: CardScrollView cardScrollView = (CardScrollView) findViewById(R.id.card_scroll_view); cardScrollView.setCardGravity(Gravity.BOTTOM); You can now test the app on an emulator, which will produce the following result: As can be seen in the previous image, the Android Studio has preview screens for both wearable shapes. Like some other previews, these are not always what you will see on a device, but they allow us to put layouts together very quickly, by dragging and dropping widgets. As we can see, the CardScrollView and CardFrame are even easier to implement than the CardFragment and also far more flexible, as we can design almost any layout we can imagine. We assigned app:layout_box here again, only this time using bottom, causing the card to be placed as low on the screen as possible. It is very important, when designing for such small screens, to keep our layouts as clean and simple as possible. Google's design principles state that wearable apps should be glanceable. This means that, as with a traditional wrist watch, the user should be able to glance at our app and immediately take in the information and return to what they were doing. Another of Google's design principle—Zero to low interaction—is only a single tap or swipe a user needs to do to interact with our app. With these principles in mind, let us create a small app, with some actual functionality. In the next section, we will take advantage of the new heart rate sensor found in many wearable devices and display current beats-per-minute on the display. Accessing sensor data The location of an Android Wear device on the user's wrist, makes it the perfect piece of hardware for fitness apps, and not surprisingly, these apps are immensely popular. As with most features of the SDK, accessing sensors is pleasantly simple, using classes such as managers and listeners and requiring only a few lines of code, as you will see by following these steps: Open the project we have been working on in this article. Replace the background image with one that might be suitable for a fitness app. I have used a simple image of a heart. Open the activity_main.xml file. Delete everything, except the root BoxInsetLayout. Place this TextView inside it: <TextView android_id="@+id/text_view" android_layout_width="match_parent" android_layout_height="wrap_content" android_layout_gravity="center_vertical" android_gravity="center" android_text="BPM" android_textColor="@color/black" android_textSize="42sp" /> Open the Manifest file in the wear module. Add the following permission inside the root manifest node: <uses-permission android_name="android.permission.BODY_SENSORS" /> Open the MainActivity.java file in the wear module. Add the following fields: private TextView textView; private SensorManager sensorManager; private Sensor sensor; Implement a SensorEventListener on the Activity: public class MainActivity extends Activity implements SensorEventListener { Implement the two methods required by the listener. Edit the onCreate() method, like this: @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = (TextView) findViewById(R.id.text_view); sensorManager = ((SensorManager) getSystemService(SENSOR_SERVICE)); sensor = sensorManager.getDefaultSensor(Sensor.TYPE_HEART_RATE); } Add this onResume() method: protected void onResume() { super.onResume(); sensorManager.registerListener(this, this.sensor, 3); } And this onPause() method: @Override protected void onPause() { super.onPause(); sensorManager.unregisterListener(this); } Edit the onSensorChanged() callback, like so: @Override public void onSensorChanged(SensorEvent event) { textView.setText("" + (int) event.values[0]); } If you do not have access to a real device, you can download a sensor simulator from here:     https://code.google.com/p/openintents/wiki/SensorSimulator The app is now ready to test. We began by adding a permission in the AndroidManifest.xml file in the appropriate module; this is something we have done before and need to do any time we are using features, that require the user's permission before installing. The inclusion of a background image may seem necessary, but an appropriate background is a real aid to glancability as the user can tell instantly which app they are looking at. It should be clear, from the way the SensorManager and the Sensor are set up in the onCreate() method, that all sensors are accessed in the same way and different sensors can be accessed with different constants. We used TYPE_HEART_RATE here, but any other sensor can be started with the appropriate constant, and all sensors can be managed with the same basic structures as we found here, the only real difference being the way each sensor returns SensorEvent.values[]. A comprehensive list of all sensors, and descriptions of the values they produce can be found at http://developer.android.com/reference/android/hardware/Sensor.html. As with any time our apps utilize functions that run in the background, it is vital that we unregister our listeners, whenever they are no longer needed, in our Activity's onPause() method. We didn't use the onAccuracyChanged() callback here, but its purpose should be clear and there are many possible apps where its use is essential. This concludes our exploration of wearable apps and how they are put together. Such devices continue to become more prevalent and the possibility of ever more imaginative uses is endless. Providing we consider why and how people use smart watches, and the like, and develop to take advantage of the location of these devices by programming glanceable interfaces that require the minimum of interactivity, Android Wear seems certain to grow in popularity and use, and the developers will continue to produce ever more innovative apps. Summary In this article, we have explored Android wearable apps and how they are put together. Despite their diminutive size and functionality, wearables offer us an enormous range of possibilities. We know now how to create and connect wearable AVDs and how to develop easily for both square and round devices. We then designed the user interface for both round and square screens. To learn more about Android UI interface designing and developing android applications, the following books published by Packt Publishing (https://www.packtpub.com/) are recommended: Android User Interface Development: Beginner's Guide, found at https://www.packtpub.com/application-development/android-user-interface-development-beginners-guide Android 4: New Features for Application Development, found at https://www.packtpub.com/application-development/android-4-new-features-application-development Resources for Article: Further resources on this subject: Understanding Material Design [Article] Speaking Java – Your First Game [Article] Mobile Game Design Best Practices [Article]
Read more
  • 0
  • 0
  • 10489

article-image-creating-compiling-and-deploying-native-projects-android-ndk
Packt
13 Feb 2012
13 min read
Save for later

Creating, Compiling, and Deploying Native Projects from the Android NDK

Packt
13 Feb 2012
13 min read
(For more resources on Android, see here.) Compiling and deploying NDK sample applications I guess you cannot wait anymore to test your new development environment. So why not compile and deploy elementary samples provided by the Android NDK first to see it in action? To get started, I propose to run HelloJni, a sample application which retrieves a character string defined inside a native C library into a Java activity (an activity in Android being more or less equivalent to an application screen). Time for action – compiling and deploying hellojni sample Let's compile and deploy HelloJni project from command line using Ant: Open a command-line prompt (or Cygwin prompt on Windows). Go to hello-jni sample directory inside the Android NDK. All the following steps have to performed from this directory: $ cd $ANDROID_NDK/samples/hello-jni Create Ant build file and all related configuration files automatically using android command (android.bat on Windows). These files describe how to compile and package an Android application: android update project –p . (Move the mouse over the image to enlarge.) Build libhello-jni native library with ndk-build, which is a wrapper Bash script around Make. Command ndk-build sets up the compilation toolchain for native C/ C++ code and calls automatically GCC version featured with the NDK. $ ndk-build Make sure your Android development device or emulator is connected and running. Compile, package, and install the final HelloJni APK (an Android application package). All these steps can be performed in one command, thanks to Ant build automation tool. Among other things, Ant runs javac to compile Java code, AAPT to package the application with its resources, and finally ADB to deploy it on the development device. Following is only a partial extract of the output: $ ant install The result should look like the following extract: Launch a shell session using adb (or adb.exe on Windows). ADB shell is similar to shells that can be found on the Linux systems: $ adb shell From this shell, launch HelloJni application on your device or emulator. To do so, use am, the Android Activity Manager. Command am allows to start Android activities, services or sending intents (that is, inter-activity messages) from command line. Command parameters come from the Android manifest: # am start -a android.intent.action.MAIN -n com.example.hellojni/com.example.hellojni.HelloJni Finally, look at your development device. HelloJni appears on the screen! What just happened? We have compiled, packaged, and deployed an official NDK sample application with Ant and SDK command-line tools. We will explore them more in later part. We have also compiled our first native C library (also called module) using the ndk-build command. This library simply returns a character string to the Java part of the application on request. Both sides of the application, the native and the Java one, communicate through Java Native Interface. JNI is a standard framework that allows Java code to explicitly call native C/C++ code with a dedicated API. Finally, we have launched HelloJni on our device from an Android shell (adb shell) with the am Activity Manager command. Command parameters passed in step 8 come from the Android manifest: com.example.hellojni is the package name and com.example.hellojni. HelloJni is the main Activity class name concatenated to the main package. <?xml version="1.0" encoding="utf-8"?><manifest package="com.example.hellojni" HIGHLIGHT android_versionCode="1" android_versionName="1.0">... <activity android_name=".HelloJni" HIGHLIGHT android_label="@string/app_name">... Automated build Because Android SDK, NDK, and their open source bricks are not bound to Eclipse or any specific IDE, creating an automated build chain or setting up a continuous integration server becomes possible. A simple bash script with Ant is enough to make it work! HelloJni sample is a little bit... let's say rustic! So what about trying something fancier? Android NDK provides a sample named San Angeles. San Angeles is a coding demo created in 2004 for the Assembly 2004 competition. It has been later ported to OpenGL ES and reused as a sample demonstration in several languages and systems, including Android. You can find more information by visiting one of the author's page: http://jet.ro/visuals/4k-intros/san-angeles-observation/. Have a go hero – compiling san angeles OpenGL demo To test this demo, you need to follow the same steps: Go to the San Angeles sample directory. Generate project files. Compile and install the final San Angeles application. Finally run it. As this application uses OpenGL ES 1, AVD emulation will work, but may be somewhat slow! You may encounter some errors while compiling the application with Ant: The reason is simple: in res/layout/ directory, main.xml file is defined. This file usually defines the main screen layout in Java application—displayed components and how they are organized. However, when Android 2.2 (API Level 8) was released, the layout_width and layout_height enumerations, which describe the way UI components should be sized, were modified: FILL_PARENT became MATCH_PARENT. But San Angeles uses API Level 4. There are basically two ways to overcome this problem. The first one is selecting the right Android version as the target. To do so, specify the target when creating Ant project files: $ android update project –p . -–target android-8 This way, build target is set to API Level 8 and MATCH_PARENT is recognized. You can also change the build target manually by editing default.properties at the project root and replacing: target=android-4 with the following line: target=android-8 The second way is more straightforward: erase the main.xml file! Indeed, this file is in fact not used by San Angeles demo, as only an OpenGL screen created programmatically is displayed, without any UI components. Target right! When compiling an Android application, always check carefully if you are using the right target platform, as some features are added or updated between Android versions. A target can also dramatically change your audience wideness because of the multiple versions of Android in the wild... Indeed, targets are moving a lot and fast on Android!. All these efforts are not in vain: it is just a pleasure to see this old-school 3D environment full of flat-shaded polygons running for the first time. So just stop reading and run it! Exploring android SDK tools Android SDK includes tools which are quite useful for developers and integrators. We have already overlooked some of them including the Android Debug Bridge and android command. Let's explore them deeper.   Android debug bridge You may have not noticed it specifically since the beginning but it has always been there, over your shoulder. The Android Debug Bridge is a multifaceted tool used as an intermediary between development environment and emulators/devices. More specifically, ADB is: A background process running on emulators and devices to receive orders or requests from an external computer. A background server on your development computer communicating with connected devices and emulators. When listing devices, ADB server is involved. When debugging, ADB server is involved. When any communication with a device happens, ADB server is involved! A client running on your development computer and communicating with devices through ADB server. That is what we have done to launch HelloJni: we got connected to our device using adb shell before issuing the required commands. ADB shell is a real Linux shell embedded in ADB client. Although not all standard commands are available, classical commands, such as ls, cd, pwd, cat, chmod, ps, and so on are executable. A few specific commands are also provided such as: logcat To display device log messages dumpsys To dump system state dmesg To dump kernel messages ADB shell is a real Swiss Army knife. It also allows manipulating your device in a flexible way, especially with root access. For example, it becomes possible to observe applications deployed in their "sandbox" (see directory /data/data) or to a list and kill currently running processes. ADB also offers other interesting options; some of them are as follows: pull <device path> <local path> To transfer a file to your computer push <local path> <device path> To transfer a file to your device or emulator install <application package> To install an application package install -r <package to reinstall> To reinstall an application, if already deployed devices To list all Android devices currently connected, including emulators reboot To restart an Android device programmatically wait-for-device To sleep, until a device or emulator is connected to your computer (for example,. in a script) start-server To launch the ADB server communicating with devices and emulators kill-server To terminate the ADB server bugreport To print the whole device state (like dumpsys) help To get an exhaustive help with all options and flags available To ease the writing of issued command, ADB provides facultative flags to specify before options: -s <device id> To target a specific device -d To target current physical device, if only one is connected (or an error message is raised) -e To target currently running emulator, if only one is connected (or an error message is raised) ADB client and its shell can be used for advanced manipulation on the system, but most of the time, it will not be necessary. ADB itself is generally used transparently. In addition, without root access to your phone, possible actions are limited. For more information, see http://developer.android.com/guide/developing/tools/adb.html. Root or not root. If you know the Android ecosystem a bit, you may have heard about rooted phones and non-rooted phones. Rooting a phone means getting root access to it, either "officially" while using development phones or using hacks with an end user phone. The main interest is to upgrade your system before the manufacturer provides updates (if any!) or to use a custom version (optimized or modified, for example, CyanogenMod). You can also do any possible (especially dangerous) manipulations that an Administrator can do (for example, deploying a custom kernel). Rooting is not an illegal operation, as you are modifying YOUR device. But not all manufacturers appreciate this practice and usually void the warranty. Have a go hero – transferring a file to SD card from command line Using the information provided, you should be able to connect to your phone like in the good old days of computers (I mean a few years ago!) and execute some basic manipulation using a shell prompt. I propose you to transfer a resource file by hand, like a music clip or a resource that you will be reading from a future program of yours. To do so, you need to open a command-line prompt and perform the following steps: Check if your device is available using adb from command line. Connect to your device using the Android Debug Bridge shell prompt. Check the content of your SD card using standard Unix ls command. Please note that ls on Android has a specific behavior as it differentiates ls mydir from ls mydir/, when mydir is a symbolic link. Create a new directory on your SD card using the classic command mkdir . Finally, transfer your file by issuing the appropriate adb command. Project configuration tool The command named android is the main entry point when manipulating not only projects but also AVDs and SDK updates. There are few options available, which are as follows: create project: This option is used to create a new Android project through command line. A few additional options must be specified to allow proper generation: -p The project path -n The project name -t The Android API target -k The Java package, which contains application's main class -a The application's main class name (Activity in Android terms) For example: $ android create project –p ./MyProjectDir –n MyProject –t android-8 –k com.mypackage –a MyActivity update project: This is what we use to create Ant project files from an existing source. It can also be used to upgrade an existing project to a new version. Main parameters are as follows: -p The project path -n To change the project name -l To include an Android library project (that is, reusable code). The path must be relative to the project directory). -t To change the Android API target There are also options to create library projects (create lib-project, update lib- project) and test projects (create test-project, update test-project). I will not go into details here as this is more related to the Java world. As for ADB, android command is your friend and can give you some help: $ android create project –help   Command android is a crucial tool to implement a continuous integration toolchain in order to compile, package, deploy, and test a project automatically entirely from command line. Have a go hero – towards continuous integration With adb, android, and ant commands, you have enough knowledge to build a minimal automatic compilation and deployment script to perform some continuous integration. I assume here that you have a versioning software available and you know how to use it. Subversion (also known as SVN) is a good candidate and can work in local (without a server). Perform the following operations: Create a new project by hand using android command. Then, create a Unix or Cygwin shell script and assign it the necessary execution rights (chmod command). All the following steps have to be scribbled in it. In the script, check out sources from your versioning system (for example, using a svn checkout command) on disk. If you do not have a versioning system, you can still copy your own project directory using Unix commands. Build the application using ant. Do not forget to check command results using $?. If the returned value is different from 0, it means an error occurred. Additionally, you can use grep or some custom tools to check potential error messages. If needed, you can deploy resources files using adb Install it on your device or on the emulator (which you can launch from the script) using ant as shown previously. You can even try to launch your application automatically and check Android logs (see logcat option in adb). Of course, your application needs to make use of logs! A free monkey to test your App! In order to automate UI testing on an Android application, an interesting utility that is provided with the Android SDK is MonkeyRunner, which can simulate user actions on a device to perform some automated UI testing. Have a look at http://developer.android.com/guide/developing/tools/monkeyrunner_concepts.html . To favor automation, a single Android shell statement can be executed from command-line as follows: adb shell ls /sdcard/   To execute a command on an Android device and retrieve its result back on your host shell, execute the following command: adb shell "ls / notexistingdir/ 1> /dev/null 2> &1; echo $?" Redirection is necessary to avoid polluting the standard output. The escape character before $? is required to avoid early interpretation by the host shell. Now you are fully prepared to automate your own build toolchain!
Read more
  • 0
  • 0
  • 10352

article-image-practical-how-recipes-android
Packt
27 Jan 2016
20 min read
Save for later

Practical How-To Recipes for Android

Packt
27 Jan 2016
20 min read
In this article by Rick Boyer and Kyle Merrifield Mew, the author of Android Application Development Cookbook - Second Edition, we'll take a look at the following recipes: Making a Flashlight with a Heads-up notification Scaling down large images to avoid out-of-memory exceptions How to get the last location Push notification using Google Cloud Messaging (For more resources related to this topic, see here.) Making a Flashlight with a Heads-up notification Android 5.0—Lollipop (API 21)—introduced a new type of notification called the Heads-up notification. Many people do not care about this new notification as it can be extremely intrusive. This is because the notification forces its way on top of other apps. (Take a look at the following screenshot.) Keep this in mind when using this type of notification. We're going to demonstrate the Heads-up notification with a Flashlight as this demonstrates a good use case scenario. Here's a screenshot showing the Heads-up notification that we'll create: If you have a device running Android 6.0, you may have noticed the new Flashlight settings option. As a demonstration, we're going to create something similar in this recipe. Getting ready Create a new project in Android Studio and call it FlashlightWithHeadsUp. When prompted for the API level, we need API 23 (or higher) for this project. Select Empty Activity when prompted for Activity Type. How to do it... Our activity layout will consist of just ToggleButton to control the flashlight mode. We'll use the setTorchMode() code and add a Heads-up notification. We'll need permission to use the vibrate option; so, start by opening the Android Manifest and follow these steps: Add the following permission: <uses-permission android_name="android.permission.VIBRATE"/> Specify that we only want a single instance of MainActivity by adding android:launchMode="singleInstance" to the <MainActivity> element. It will look like this: <activity android_name=".MainActivity"     android_launchMode="singleInstance"> With the changes made to the Manifest, open the activity_main.xml layout, and replace the existing <TextView> element with this <ToggleButton> code: <ToggleButton     android_id="@+id/buttonLight"     android_layout_width="wrap_content"     android_layout_height="wrap_content"     android_text="Flashlight"     android_layout_centerVertical="true"     android_layout_centerHorizontal="true"     android_onClick="clickLight"/> Now, open ActivityMain.java and add the following global variables: private static final String ACTION_STOP="STOP"; private CameraManager mCameraManager; private String mCameraId=null; private ToggleButton mButtonLight; Add the following code to onCreate() to set up the camera: mButtonLight = (ToggleButton)findViewById(R.id.buttonLight); mCameraManager = (CameraManager) this.getSystemService(Context.CAMERA_SERVICE); mCameraId = getCameraId(); if (mCameraId==null) {     mButtonLight.setEnabled(false); } else {     mButtonLight.setEnabled(true); } Add the following method to handle the response when the user presses the notification: @Override protected void onNewIntent(Intent intent) {     super.onNewIntent(intent);     if (ACTION_STOP.equals(intent.getAction())) {         setFlashlight(false);     } } Add the method to get the camera ID: private String getCameraId()  {     try {         String[] ids = mCameraManager.getCameraIdList();         for (String id : ids) {             CameraCharacteristics c = mCameraManager.getCameraCharacteristics(id);             Boolean flashAvailable = c.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);             Integer facingDirection = c.get(CameraCharacteristics.LENS_FACING);             if (flashAvailable != null && flashAvailable && facingDirection != null && facingDirection == CameraCharacteristics.LENS_FACING_BACK) {                 return id;             }         }     } catch (CameraAccessException e) {         e.printStackTrace();     }     return null; } Add these two methods to handle the flashlight mode: public void clickLight(View view) {     setFlashlight(mButtonLight.isChecked());     if (mButtonLight.isChecked()) {         showNotification();     } }   private void setFlashlight(boolean enabled) {     mButtonLight.setChecked(enabled);     try {         mCameraManager.setTorchMode(mCameraId, enabled);     } catch (CameraAccessException e) {         e.printStackTrace();     } } Finally, add this method to create the notification: private void showNotification() {     Intent activityIntent = new Intent(this,MainActivity.class);     activityIntent.setAction(ACTION_STOP);     PendingIntent pendingIntent = PendingIntent.getActivity(this,0,activityIntent,0);     final Builder notificationBuilder = new Builder(this)             .setContentTitle("Flashlight")             .setContentText("Press to turn off the flashlight")             .setSmallIcon(R.mipmap.ic_launcher)             .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))             .setContentIntent(pendingIntent)             .setVibrate(new long[]{DEFAULT_VIBRATE})             .setPriority(PRIORITY_MAX);     NotificationManager notificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);     notificationManager.notify(0, notificationBuilder.build()); } You're ready to run the application on a physical device. As seen in the preceding steps, you'll need an Android 6.0 (or higher) device, with an outward facing camera flash. How it works... Since this recipe uses the same flashlight code, we'll jump into the showNotification() method. Most of the notification builder calls are the same as the ones seen in previous examples, but there are two significant differences: .setVibrate() .setPriority(PRIORITY_MAX) Notifications will not be escalated to Heads-up notifications unless the priority is high (or above) and uses either vibrate or sound. Take a look at this from the developer documentation (http://developer.android.com/reference/android/app/Notification.html#headsUpContentView): "At its discretion, the system UI may choose to show this as a heads-up notification". We create the PendingIntent method as we've done previously, but, here, we set the action using this code: activityIntent.setAction(ACTION_STOP); We set the app to only allow a single instance in the AndroidManifest method as we don't want to start a new instance of the app when the user presses the notification. The PendingIntent method we created sets the action, which we can check out in the onNewIntent() callback. If the user opens the app without pressing the notification, they can still disable the flashlight using the ToggleButton. There's more... We can use a custom layout with notifications. Use the following method on the builder to specify its layout: headsupContentView() Scaling down large images to avoid out-of-memory exceptions Working with images can be very memory-intensive, often resulting in your application crashing due to an out-of-memory exception. This is especially true for pictures taken with the device camera as they often have a much higher resolution than the device itself. Since loading a higher-resolution image than the UI supports doesn't provide any visual benefit, this recipe will demonstrate how to take smaller samples of the image for display. We'll use BitmapFactory to first check the image size, and we'll then load a scaled down image. Here's a screenshot from this recipe, showing a thumbnail of a very large image: Getting ready Create a new project in Android Studio and call it LoadLargeImage. Use the default Phone & Tablet options, and select Empty Activity when prompted for the Activity Type. We'll need a large image for this recipe, so we've referred to https://pixabay.com/ for an image. Since the image itself doesn't matter, we downloaded the first image that shown at the time. (The full size of image is 6000 x 4000 and 3.4 MB.) How to do it... As stated previously, we need a large image to demonstrate the scaling. Once you have the image, follow these steps: Copy the image to res/drawable as image_large.jpg (use the appropriate extension if you choose a different file type) Open activity_main.xml and replace the existing TextView with the following ImageView: <ImageView     android_id="@+id/imageViewThumbnail"     android_layout_width="100dp"     android_layout_height="100dp"     android_layout_centerInParent="true" /> Now, open MainActivity.java and add this method, which we'll explain as follows: public Bitmap loadSampledResource(int imageID, int targetHeight, int targetWidth) {     final BitmapFactory.Options options = new BitmapFactory.Options();     options.inJustDecodeBounds = true;     BitmapFactory.decodeResource(getResources(), imageID, options);     final int originalHeight = options.outHeight;     final int originalWidth = options.outWidth;     int inSampleSize = 1;     while ((originalHeight / (inSampleSize *2)) > targetHeight && (originalWidth / (inSampleSize *2)) > targetWidth) {         inSampleSize *= 2;     }     options.inSampleSize=inSampleSize;     options.inJustDecodeBounds = false;     return BitmapFactory.decodeResource(getResources(), imageID, options); } Add the following code to the existing onCreate() method: ImageView imageView = (ImageView)findViewById(R.id.imageViewThumbnail); imageView.setImageBitmap(loadSampledResource(R.drawable.image_large, 100, 100)); Run the application on a device or emulator. How it works... The purpose of the loadSampledResource() method is to load a smaller image to reduce the memory consumption of the image. If we attempted to load the full image chosen from https://pixabay.com/, the app would require over 3 MB of RAM to load. That's more memory than most devices can handle (at the moment, anyway), and even if it could be loaded completely, it would provide no visual benefit to our thumbnail view. To avoid an out-of-memory situation, we use the inSampleSize property of BitmapFactory. You will find options to reduce or subsample the image. (If we set inSampleSize=2, it will reduce the image in half. If we use inSampleSize=4, it will reduce the image by ¼.) To calculate inSampleSize, we first need to know the image size. We can use the inJustDecodeBounds property, as follows: options.inJustDecodeBounds = true; This tells BitmapFactory to get the image dimensions without actually storing the contents of the image. Once we know the image size, we calculate the sample using this code: while ((originalHeight / (inSampleSize *2)) > targetHeight &&             (originalWidth / (inSampleSize *2)) > targetWidth) {         inSampleSize *= 2;     } The purpose of this code is to determine the largest sample size that does not reduce the image below the target dimensions. To do this, we double the sample size, and check whether the size exceeds the target size dimensions. If it doesn't, we save the doubled sample size and repeat the process. Once the reduced size falls below the target dimensions, we use the last saved inSampleSize. From the inSampleSize documentation: Note that the decoder uses a final value that's based on powers of 2; any other value will be rounded down to the nearest power of 2. Once we have the sample size, we set the inSampleSize property. We also set inJustDecodeBounds to false in order to make it load normally. Here is the code to do this: options.inSampleSize = inSampleSize; options.inJustDecodeBounds = false; It's important to note that this recipe illustrates the concept of applying a task in your own application. Loading and processing images can be a long operation, which could cause your application to stop responding. This is not a good thing and could cause Android to show the Application Not Responding (ANR) dialog. It is recommended that you perform long tasks on a background thread to keep your UI thread responsive. There's more... It's important to note that the targetHeight and targetWidth parameters we pass to the loadSampledResource()method do not actually set the size of the image. If you run the application using the same sized image we used earlier, the sample size will be 32, resulting in a loaded image that is 187 x 125 in size. If your layout needs an image of a specific size, either set the size in the layout file; otherwise, you can modify the size directly using the Bitmap class. See also The inSampleSize() documentation at https://developer.android.com/reference/android/graphics/BitmapFactory.Options.html#inSampleSize How to get the last Location We'll start this with a simple recipe that is commonly needed: how to get the last known location. This is an easy-to-use API with very little overhead resource drain (which means that your app won't be responsible for killing the battery life). This recipe also provides a good introduction to setting up the Google Location APIs. Getting ready Create a new project in Android Studio and call it GetLastLocation. Use the default Phone & Tablet options, and select Empty Activity when prompted for the Activity Type. How to do it... First, we'll add the necessary permissions to the Android Manifest. We'll then create a layout with a Button and TextView. Finally, we'll create GoogleAPIClient to access the previous location. Open the Android Manifest and follow these steps: Add the following permission: <uses-permission android_name="android.permission.ACCESS_COARSE_LOCATION"/> Open the build.gradle file (Module: app), as shown in this screenshot: Add the following statement to the dependencies section: compile 'com.google.android.gms:play-services:8.4.0' Open activity_main.xml and replace the existing TextView with the following XML: <TextView     android_id="@+id/textView"     android_layout_width="wrap_content"     android_layout_height="wrap_content" /> <Button     android_id="@+id/button"     android_layout_width="wrap_content"     android_layout_height="wrap_content"     android_text="Get Location" android_layout_centerInParent="true"     android_onClick="getLocation"/> Open MainActivity.java and add the following global variables: GoogleApiClient mGoogleApiClient; TextView mTextView; Button mButton; Add the class for ConnectionCallbacks: GoogleApiClient.ConnectionCallbacks mConnectionCallbacks = new GoogleApiClient.ConnectionCallbacks() {     @Override     public void onConnected(Bundle bundle) {         mButton.setEnabled(true);     }     @Override     public void onConnectionSuspended(int i) {} }; Add the class to handle the OnConnectionFailedListener callback: GoogleApiClient.OnConnectionFailedListener mOnConnectionFailedListener = new GoogleApiClient.OnConnectionFailedListener() {     @Override     public void onConnectionFailed(ConnectionResult connectionResult) {         Toast.makeText(MainActivity.this, connectionResult.toString(), Toast.LENGTH_LONG).show();     } }; Add the following code to the existing onCreate() method: mTextView = (TextView) findViewById(R.id.textView); mButton = (Button) findViewById(R.id.button); mButton.setEnabled(false); setupGoogleApiClient(); Add the method to set up GoogleAPIClient: protected synchronized void setupGoogleApiClient() {     mGoogleApiClient = new GoogleApiClient.Builder(this)             .addConnectionCallbacks(mConnectionCallbacks)             .addOnConnectionFailedListener(mOnConnectionFailedListener)             .addApi(LocationServices.API)             .build();     mGoogleApiClient.connect(); } Add the method for the button click: public void getLocation(View view) {     try {         Location lastLocation = LocationServices.FusedLocationApi.getLastLocation(                 mGoogleApiClient);         if (lastLocation != null) {             mTextView.setText(                     DateFormat.getTimeInstance().format(lastLocation.getTime()) + "n" +                             "Latitude="+lastLocation.getLatitude()+"n"+                             "Longitude="+lastLocation.getLongitude());         } else {             Toast.makeText(MainActivity.this, "null", Toast.LENGTH_LONG).show();         }     }     catch (SecurityException e) {} } You're ready to run the application on a device or emulator. How it works... Before we can call the getLastLocation() method, we need to set up GoogleApiClient. We call GoogleApiClient.Builder in our setupGoogleApiClient() method, and then connect to the library. When the library is ready, it calls our ConnectionCallbacks.onConnected() method. For demonstration purposes, this is where we enable the button. We used a button to show that we can call getLastLocation() on demand; it's not a one-time call. The system is responsible for updating the location and may return the same previous location on repeated calls. (This can be seen in the timestamp—it's the location timestamp, not the timestamp that appears when the button is pressed.) This approach of calling the location non-demand can be useful in situations where you only need the location when something happens in your app (such as geocoding an object). Since the system is responsible for the updates of the location, your app will not be responsible for draining your battery due to location updates. The accuracy of the Location object we receive is based on our permission setting. We used ACCESS_COARSE_LOCATION, but if we want higher accuracy, we can request ACCESS_FINE_LOCATION instead using the following permission: <uses-permission android_name="android.permission.ACCESS_FINE_LOCATION"/> Lastly, to keep the code focused on GoogleApiClient, we just wrap getLastLocation() with SecurityException. In a production application, you should check and request the permission. There's more... If a problem occurs when establishing a connection with GoogleApiClient, OnConnectionFailedListener is called. In this example, we will display a toast. Testing the location can be a challenge since it's difficult to actually move the device when testing and debugging it. Fortunately, we have the ability to simulate GPS data with the emulator. (It is possible to create mock locations on a physical device as well, but it's not as easy.) Mock Locations There are three ways to simulate locations using the emulator: Android Studio DDMS The Geo command via Telnet To set a mock location in Android Studio, follow these steps: Go to the Tools | Android | Android Device Monitor menu. Select the Emulator Control tab in the Devices window. Enter GPS coordinates under Location Controls. Here's a screenshot showing Location Controls: Important: Simulating the location works by sending GPS data. Therefore, for your app to receive the mock location, it will need to receive GPS data. Testing lastLocation() may not send the mock GPS data since it doesn't rely solely on GPS to determine the location of the device. (We can't force the system to use any specific location sensor; we can only make a request. The system will choose the optimum solution to deliver results.) See also How to set up Google Play Services at https://developers.google.com/android/guides/setup FusedLocationProviderApi at https://developers.google.com/android/reference/com/google/android/gms/location/FusedLocationProviderApi Push notification using Google Cloud Messaging Google Cloud Messaging (GCM), Google's version of a push notification, allows your application to receive messages. The idea is similar to SMS messages but much more flexible. There are three components of GCM: Your server (this is where you initiate the message) Google's GCM server An Android device (though GCM is also available on other platforms) When the user starts the application, your code needs to connect to the GCM server and obtain a device token, and then send this token to your server. Your server is responsible for initiating the message and passing it to the GCM server. Your server needs to track the device tokens to be sent when initiating the message (your server tells the GCM server which device tokens to send). You can implement your own server or chose to use one of many services available (the Simple Testing Option section offers an option to verify whether your code works). This recipe will walk you through the steps needed to add GCM using the current (version 8.3) Google Services library. Before getting to the steps, it's worth noting that GCM is supported all the way back to API 8 as long as the user has a Google account. A Google account is not required after installing Android 4.0.4. Getting ready Create a new project in Android Studio and call it GCM. Use the default Phone & Tablet options, and select Empty Activity when prompted for the Activity Type. Google Cloud Messaging uses the Google Services Plugin, which requires a Google Services Configuration File, available from the Google Developer Console. To create the configuration file, you will need the following information: The name of your application package When you have the information, log into https://developers.google.com/mobile/add, and follow the wizard to enable Google Cloud Messaging for your app Note that if you download the source files, you will need to create a new package name when following the steps as the existing package name has already been registered. How to do it... After completing the preceding section, follow these steps: Copy the google-services.json file you downloaded in the Getting Ready section to your app folder (<project folder>GCMapp). Open the project Gradle build file called build.gradle (project: GCM). Add the following to the build script dependencies section: classpath 'com.google.gms:google-services:1.5.0-beta2' Open the Gradle app module build file, called build.gradle (module: app), and add the following statement to the beginning of the file (above the android section): apply plugin: 'com.google.gms.google-services' In the same module build file, as seen in step 3, add the following statement to the dependencies section: compile 'com.google.android.gms:play-services-auth:8.3.0' Open the Android Manifest and add the following permissions: <uses-permission android_name="android.permission.WAKE_LOCK" /> <permission android_name="<packageName >.permission.C2D_MESSAGE"   android_protectionLevel="signature" /> <uses-permission android_name="<packageName >.permission.C2D_MESSAGE" /> Within the <application> element, add the following <receiver> and <service> declarations (these should be at the same level as <activity>): <receiver     android_name="com.google.android.gms.gcm.GcmReceiver"     android_exported="true"     android_permission="com.google.android.c2dm.permission.SEND" > <intent-filter> <action android_name="com.google.android.c2dm.intent.RECEIVE" /> <category android_name="<packageName>" /> <action android_name="com.google.android.c2dm.intent.REGISTRATION" /> </intent-filter> </receiver> <service     android_name=".GCMService"     android_exported="false" > <intent-filter> <action android_name="com.google.android.c2dm.intent.GCM_RECEIVED_ACTION"/> <action android_name="com.google.android.c2dm.intent.RECEIVE" /> </intent-filter> </service> <service     android_name=".GCMInstanceService"     android_exported="false"> <intent-filter> <action android_name="com.google.android.gms.iid.InstanceID" /> </intent-filter> </service> <service     android_name=".GCMRegistrationService"     android_exported="false"> </service> Create a new Java class, called GCMRegistrationService, that extends IntentService, as follows: public class GCMRegistrationService extends IntentService {     private final String SENT_TOKEN="SENT_TOKEN";     public GCMRegistrationService() {         super("GCMRegistrationService");     }     @Override     protected void onHandleIntent(Intent intent) {         super.onCreate();         SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);         try {             InstanceID instanceID = InstanceID.getInstance(this);             String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId),                     GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);             Log.i("GCMRegistrationService", "GCM Registration Token: " + token);             //sendTokenToServer(token);             sharedPreferences.edit().putBoolean(SENT_TOKEN, true).apply();         } catch (Exception e) {             sharedPreferences.edit().putBoolean(SENT_TOKEN, false).apply();         }     } } Create a new Java class, called GCMInstanceServicethat, that extends InstanceIDListenerServiceas, as follows: public class GCMInstanceService extends InstanceIDListenerService {     @Override          public void onTokenRefresh() {         Intent intent = new Intent(this, GCMRegistrationService.class);         startService(intent);     } } Create a new Java class, called GCMServicethat, that extends GcmListenerServiceas, as follows: public class GCMService extends GcmListenerService {     @Override     public void onMessageReceived(String from, Bundle data) {         super.onMessageReceived(from, data);         Log.i("GCMService", "onMessageReceived(): " + data.toString());     } } Add the following code to the existing onCreate() callback: Intent intent = new Intent(this, GCMRegistrationService.class); startService(intent); You're ready to run the application on a device or emulator. How it works... Most of the actual GCM code is encapsulated within the Google APIs, simplifying their implementation. We just have to set up the project to include the Google Services and give our app the required permissions. Important: When adding the permissions in steps 5 and 6, replace the <packageName> placeholder with your application's package name. The most complicated aspect of GCM is probably the multiple services that are required. Even though the code in each service is minimal, each service has a specific task. There are two main aspects of GCM: Registering the app with the GCM server Receiving messages This is the code to register with the GCM server: String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId),         GoogleCloudMessaging.INSTANCE_ID_SCOPE, null); We don't call getToken() in the Activity because it could block the UI thread. Instead, we call GCMRegistrationService, which handles the call in a background thread. After you receive the device token, you need to send it to your server as it is needed when initiating a message. Receiving a GCM message is handled in GCMService, which extends GcmListenerService. Since the Google API already handles most of the work, all we have to do respond to the onMessageReceived() callback. There's more... To make it easier to type, we left out an important Google Services API verification, which should be included in any production application. Instead of calling GCMRegistrationService directly, as we did in onCreate() previously, first check whether the Google API Service is available. Here's an example that shows how to call the isGooglePlayServicesAvailable() method: private boolean isGooglePlayServicesAvailable() {     GoogleApiAvailability googleApiAvailability = GoogleApiAvailability.getInstance();     int resultCode = googleApiAvailability.isGooglePlayServicesAvailable(this);     if (resultCode != ConnectionResult.SUCCESS) {         if (googleApiAvailability.isUserResolvableError(resultCode)) {             googleApiAvailability.getErrorDialog(this, resultCode, PLAY_SERVICES_RESOLUTION_REQUEST)                     .show();         } else {             Toast.makeText(MainActivity.this, "Unsupported Device", Toast.LENGTH_SHORT).show();             finish();         }         return false;     }     return true; } Then, change the onCreate() code to call this method first: if (isGooglePlayServicesAvailable()) {     Intent intent = new Intent(this, GCMRegistrationService.class);     startService(intent); } Simple testing option To verify whether your code is working correctly, a testing application was created and posted on Google Play. This app will run on both a physical device and an emulator. The Google Play listing also includes a link to download the source code to run the project directly, making it easier to enter the required fields. Take a look at GCM (Push Notification) Tester at https://play.google.com/store/apps/details?id=com.eboyer.gcmtester. See also Google Cloud Messaging at https://developers.google.com/android/reference/com/google/android/gms/gcm/GoogleCloudMessaging GCM Connection Server at https://developers.google.com/cloud-messaging/server Summary In this article, we learned how to make a Flashlight with a Heads-up notification, scaling down large images to avoid out-of-memory exceptions, how to get last location and using push notification with GCM. Resources for Article: Further resources on this subject: Introduction to GameMaker: Studio [article] Working with Xamarin.Android [article] The Art of Android Development Using Android Studio [article]
Read more
  • 0
  • 0
  • 9104

article-image-creating-user-interfaces
Packt
15 Oct 2013
6 min read
Save for later

Creating User Interfaces

Packt
15 Oct 2013
6 min read
When creating an Android application, we have to be aware of the existence of multiple screen sizes and screen resolutions. It is important to check how our layouts are displayed in different screen configurations. To accomplish this, Android Studio provides a functionality to change the layout preview when we are in the design mode. We can find this functionality in the toolbar, the device definition option used in the preview is by default Nexus 4. Click on it to open the list of available device definitions. Try some of them. The difference between a tablet device and a device like the Nexus one are very notable. We should adapt the views to all the screen configurations our application supports to ensure they are displayed optimally. The device definitions indicate the screen inches, the resolution, and the screen density. Android divides into ldpi, mdpi, hdpi, xhdpi, and even xxhdpi the screen densities. ldpi (low-density dots per inch): About 120 dpi mdpi (medium-density dots per inch): About 160 dpi hdpi (high-density dots per inch): About 240 dpi xhdpi (extra-high-density dots per inch): About 320 dpi xxhdpi (extra-extra-high-density dots per inch): About 480 dpi The last dashboards published by Google show that most devices have high-density screens (34.3 percent), followed by xhdpi (23.7 percent) and mdpi (23.5 percent). Therefore, we can cover 81.5 percent of the devices by testing our application using these three screen densities. Official Android dashboards are available at http://developer.android.com/about/dashboards. Another issue to keep in mind is the device orientation. Do we want to support the landscape mode in our application? If the answer is yes, we have to test our layouts in the landscape orientation. On the toolbar, click on the layout state option to change the mode from portrait to landscape or from landscape to portrait. In the case that our application supports the landscape mode and the layout does not display as expected in this orientation, we may want to create a variation of the layout. Click on the first icon of the toolbar, that is, the configuration option, and select the option Create Landscape Variation. A new layout will be opened in the editor. This layout has been created in the resources folder, under the directory layout-land and using the same name as the portrait layout: /src/main/res/layout-land/activity_main.xml. Now we can edit the new layout variation perfectly conformed to the landscape mode. Similarly, we can create a variation of the layout for xlarge screens. Select the option Create layout-xlarge Variation. The new layout will be created in the layout xlarge folder: /src/main/res/layout-xlarge/activity_main.xml. Android divides into small, normal, large, and xlarge the actual screen sizes: small: Screens classified in this category are at least 426 dp x 320 dp normal: Screens classified in this category are at least 470 dp x 320 dp large: Screens classified in this category are at least 640 dp x 480 dp xlarge: Screens classified in this category are at least 960 dp x 720 dp A dp is a density independent pixel, equivalent to one physical pixel on a 160 dpi screen. The last dashboards published by Google show that most devices have a normal screen size (79.6 percent). If you want to cover a bigger percentage of devices, test your application by also using a small screen (9.5 percent), so the coverage will be 89.1 percent of devices. To display multiple device configurations at the same time, in the toolbar click on the configuration option and select the option Preview All Screen Sizes, or click on the Preview Representative Sample to open just the most important screen sizes. We can also delete any of the samples by clicking on it using the right mouse button and selecting the Delete option of the menu. Another useful action of this menu is the Save screenshot option, which allows us to take a screenshot of the layout preview. If we create some layout variations, we can preview all of them selecting the option Preview Layout Versions. Changing the UI theme Layouts and widgets are created using the default UI theme of our project. We can change the appearance of the elements of the UI by creating styles. Styles can be grouped to create a theme and a theme can be applied to a whole activity or application. Some themes are provided by default, such as the Holo style. Styles and themes are created as resources under the /src/res/values folder. Open the main layout using the graphical editor. The selected theme for our layout is indicated in the toolbar: AppTheme. This theme was created for our project and can be found in the styles file (/src/res/values/styles.xml). Open the styles file and notice that this theme is an extension of another theme (Theme.Light). To custom our theme, edit the styles file. For example, add the next line in the AppTheme definition to change the window background color: <style name="AppTheme" parent="AppBaseTheme"> <item name="android:windowBackground">#dddddd</item> </style> Save the file and switch to the layout tab. The background is now light gray. This background color will be applied to all our layouts due to the fact that we configured it in the theme and not just in the layout. To completely change the layout theme, click on the theme option from the toolbar in the graphical editor. The theme selector dialog is now opened, displaying a list of the available themes. The themes created in our own project are listed in the Project Themes section. The section Manifest Themes shows the theme configured in the application manifest file (/src/main/AndroidManifest.xml). The All section lists all the available themes. Summary In this article, we have seen how to develop and build Android applications with this new IDE.uide. It also shows how to support multiple screens and change their properties using the SDK. The changing of UI themes for the devices is also discussed, along with its properties. The main focus was on the creation of the user interfaces using both the graphical view and the text-based view. Resources for Article: Further resources on this subject: Creating Dynamic UI with Android Fragments Building Android (Must know) Android Fragmentation Management
Read more
  • 0
  • 0
  • 8732
article-image-introducing-tablayout
Packt
29 Oct 2015
14 min read
Save for later

Introducing TabLayout

Packt
29 Oct 2015
14 min read
 In this article by Antonio Pachón, author of the book, Mastering Android Application Development, we take a look on the TabLayout design library and the different activities you can do with it. The TabLayout design library allows us to have fixed or scrollable tabs with text, icons, or a customized view. You would remember from the first instance of customizing tabs in this book that it isn't very easy to do, and to change from scrolling to fixed tabs, we need different implementations. (For more resources related to this topic, see here.) We want to change the color and design of the tabs now to be fixed; for this, we need to first go to activity_main.xml and add TabLayout, removing the previous PagerTabStrip. Our view will look as follows: <?xml version="1.0" encoding="utf-8"?> <LinearLayout     android_layout_height="fill_parent"     android_layout_width="fill_parent"     android_orientation="vertical"     >       <android.support.design.widget.TabLayout         android_id="@+id/tab_layout"         android_layout_width="match_parent"         android_layout_height="50dp"/>       <android.support.v4.view.ViewPager           android_id="@+id/pager"         android_layout_width="match_parent"         android_layout_height="wrap_content">       </android.support.v4.view.ViewPager>   </LinearLayout> When we have this, we need to add tabs to TabLayout. There are two ways to do this; one is to create the tabs manually as follows: tabLayout.addTab(tabLayout.newTab().setText("Tab 1")); The second way, which is the one we'll use, is to set the view pager to TabLayout. In our example, MainActivity.java should look as follows: public class MainActivity extends ActionBarActivity {       @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_main);           MyPagerAdapter adapter = new         MyPagerAdapter(getSupportFragmentManager());         ViewPager viewPager = (ViewPager)         findViewById(R.id.pager);         viewPager.setAdapter(adapter);         TabLayout tabLayout = (TabLayout)         findViewById(R.id.tab_layout);         tabLayout.setupWithViewPager(viewPager);         }     @Override     protected void attachBaseContext(Context newBase) {         super.attachBaseContext(CalligraphyContextWrapper         .wrap(newBase));     } } If we don't specify any color, TabLayout will use the default color from the theme, and the position of the tabs will be fixed. Our new tab bar will look as follows: Toolbar, action bar, and app bar Before continuing to add motion and animation to our app, we need to clarify the concepts of toolbar, the action bar, the app bar, and AppBarLayout, which might cause a bit of confusion. The action bar and app bar are the same component; app bar is just a new name that has been acquired in material design. This is the opaque bar fixed at the top of our activity that usually shows the title of the app, navigation options, and the different actions. The icon is or isn't displayed depending on the theme. Since Android 3.0, the theme Holo or any of its descendants is used by default for the action bar. Moving onto the next concept, the toolbar; introduced in API 21, Andorid Lollipop, it is a generalization of the action bar that doesn't need to be fixed at the top of the activity. We can specify whether a toolbar is to act as the activity action bar with the setActionBar() method. This means that a toolbar can act as an action bar depending on what we want. If we create a toolbar and set it as an action bar, we must use a theme with the .NoActionBar option to avoid having a duplicated action bar. Otherwise, we would have the one that comes by default in a theme along with the toolbar that we have created as the action bar. A new element, called AppBarLayout, has been introduced in the design support library; it is LinearLayout intended to contain the toolbar to display animations based on scrolling events. We can specify the behavior while scrolling in the children with the app:layout_scrollFlag attribute. AppBarLayout is intended to be contained in CoordinatorLayout—the component introduced as well in the design support library—which we will describe in the following section. Adding motion with CoordinatorLayout CoordinatorLayout allows us to add motion to our app, connecting touch events and gestures with views. We can coordinate a scroll movement with the collapsing animation of a view, for instance. These gestures or touch events are handled by the Coordinator.Behaviour class; AppBarLayout already has this private class. If we want to use this motion with a custom view, we would have to create this behavior ourselves. CoordinatorLayout can be implemented at the top level of our app, so we can combine this with the application bar or any element inside our activity or fragment. It also can be implemented as a container to interact with its child views. Continuing with our app, we will show a full view of a job offer when we click on a card. This will be displayed in a new activity. This activity will contain a toolbar showing the title of the job offer and logo of the company. If the description is long, we will need to scroll down to read it, and at the same time, we want to collapse the logo at the top, as it is not relevant anymore. In the same way, while scrolling back up, we want it to expand it again. To control the collapsing of the toolbar we will need CollapsingToolbarLayout. The description will be contained in NestedScrollView, which is a scroll view from the android v4 support library. The reason to use NestedScrollView is that this class can propagate the scroll events to the toolbar, while ScrollView can't. Ensure that compile com.android.support:support-v4:22.2.0 is up to date. So, for now, we can just place an image from the drawable folder to implement the CoordinatorLayout functionality. Our offer detail view, activity_offer_detail.xml, will look as follows: <android.support.design.widget.CoordinatorLayout     android_layout_width="match_parent"     android_layout_height="match_parent">      <android.support.design.widget.AppBarLayout         android_id="@+id/appbar"         android_layout_height="256dp"         android_layout_width="match_parent">         <android.support.design.widget.CollapsingToolbarLayout             android_id="@+id/collapsingtoolbar"             android_layout_width="match_parent"             android_layout_height="match_parent"             app_layout_scrollFlags="scroll|exitUntilCollapsed">               <ImageView                 android_id="@+id/logo"                 android_layout_width="match_parent"                 android_layout_height="match_parent"                 android_scaleType="centerInside"                 android_src="@drawable/googlelogo"                 app_layout_collapseMode="parallax" />             <android.support.v7.widget.Toolbar                 android_id="@+id/toolbar"                 android:layout_height="?attr/actionBarSize"                 android_layout_width="match_parent"                 app_layout_collapseMode="pin"/>         </android.support.design.widget.CollapsingToolbarLayout>     </android.support.design.widget.AppBarLayout>     <android.support.v4.widget.NestedScrollView         android_layout_width="fill_parent"         android_layout_height="fill_parent"         android_paddingLeft="20dp"         android_paddingRight="20dp"         app_layout_behavior=         "@string/appbar_scrolling_view_behavior">              <TextView                 android_id="@+id/rowJobOfferDesc"                 android_layout_width="fill_parent"                 android_layout_height="fill_parent"                 android_text="Long scrollabe text"                   android_textColor="#999"                 android_textSize="18sp"                 />      </android.support.v4.widget.NestedScrollView>  </android.support.design.widget.CoordinatorLayout> As you can see here, the CollapsingToolbar layout reacts to the scroll flag and tells its children how to react. The toolbar is pinned at the top, always remaining visible, app:layout_collapseMode="pin" however the logo will disappear with a parallax effect app:layout_collapseMode="parallax". Don't forget to add to NestedScrollview to the app:layout_behavior="@string/appbar_scrolling_view_behavior" attribute and clean the project to generate this string resource internally. If you have problems, you can set the string directly by typing "android.support.design.widget.AppBarLayout$ScrollingViewBehavior", and this will help you to identify the issue. When we click on a job offer, we need to navigate to OfferDetailActivity and send information about the offer. As you probably know from the beginner level, to send information between activities we use intents. In these intents, we can put the data or serialized objects to be able to send an object of the JobOffer type we have to make the The JobOffer class implements Serialization. Once we have done this, we can detect the click on the element in JobOffersAdapter: public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener{     public TextView textViewName;     public TextView textViewDescription;       public MyViewHolder(View v){         super(v);         textViewName =         (TextView)v.findViewById(R.id.rowJobOfferTitle);         textViewDescription =         (TextView)v.findViewById(R.id.rowJobOfferDesc);         v.setOnClickListener(this);         v.setOnLongClickListener(this);     }     @Override     public void onClick(View view) {             Intent intent = new Intent(view.getContext(),             OfferDetailActivity.class);             JobOffer selectedJobOffer =             mOfferList.get(getPosition());             intent.putExtra("job_title",             selectedJobOffer.getTitle());             intent.putExtra("job_description",             selectedJobOffer.getDescription());             view.getContext().startActivity(intent);     } Once we start the activity, we need to retrieve the title and set it to the toolbar. Add a long text to the TextView description inside NestedScrollView to first test with dummy data. We want to be able to scroll to test the animation: public class OfferDetailActivity extends AppCompatActivity {     @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_offer_detail);         String job_title =         getIntent().getStringExtra("job_title");         CollapsingToolbarLayout collapsingToolbar =         (CollapsingToolbarLayout)         findViewById(R.id.collapsingtoolbar);         collapsingToolbar.setTitle(job_title);     } } Finally, ensure that your styles.xml file in the folder values uses a theme with no action bar by default: <resources>     <!-- Base application theme. -->     <style name="AppTheme"     parent="Theme.AppCompat.Light.NoActionBar">         <!-- Customize your theme here. -->     </style> </resources> We are now ready to test the behavior of the app. Launch it and scroll down. Take a look at how the image collapses and the toolbar is pinned at the top. It will look similar to this: We are missing an attribute to achieve a nice effect in the animation. Just collapsing the image doesn't collapse it enough; we need to make the image disappear in a smooth way and be replaced by the background color of the toolbar. Add the contentScrim attribute to CollapsingToolbarLayout, and this will fade in the image as is collapsing using the primary color of the theme, which is the same used by the toolbar at the moment: <android.support.design.widget.CollapsingToolbarLayout     android_id="@+id/collapsingtoolbar"     android_layout_width="match_parent"     android_layout_height="match_parent"     app_layout_scrollFlags="scroll|exitUntilCollapsed"     app_contentScrim="?attr/colorPrimary"> With this attribute, the app looks better when collapsed and expanded: We just need to style the app a bit more by changing colors and adding padding to the image; we can change the colors of the theme in styles.xml through the following code: <resources>      <!-- Base application theme. -->     <style name="AppTheme"     parent="Theme.AppCompat.Light.NoActionBar">         <item name="colorPrimary">#8bc34a</item>         <item name="colorPrimaryDark">#33691e</item>         <item name="colorAccent">#FF4081</item>     </style> </resources> Resize AppBarLayout to 190dp and add 50dp of paddingLeft and paddingRight to ImageView to achieve the following result: Summary In this article we learned what the TabLayout design library is and the different activities you can do with it. Resources for Article: Further resources on this subject: Using Resources[article] Prerequisites for a Map Application[article] Remote Desktop to Your Pi from Everywhere [article]
Read more
  • 0
  • 0
  • 8449

article-image-speeding-gradle-builds-android
Packt
16 Jul 2015
7 min read
Save for later

Speeding up Gradle builds for Android

Packt
16 Jul 2015
7 min read
In this article by Kevin Pelgrims, the author of the book, Gradle for Android, we will cover a few tips and tricks that will help speed up the Gradle builds. A lot of Android developers that start using Gradle complain about the prolonged compilation time. Builds can take longer than they do with Ant, because Gradle has three phases in the build lifecycle that it goes through every time you execute a task. This makes the whole process very configurable, but also quite slow. Luckily, there are several ways to speed up Gradle builds. Gradle properties One way to tweak the speed of a Gradle build is to change some of the default settings. You can enable parallel builds by setting a property in a gradle.properties file that is placed in the root of a project. All you need to do is add the following line: org.gradle.parallel=true Another easy win is to enable the Gradle daemon, which starts a background process when you run a build the first time. Any subsequent builds will then reuse that background process, thus cutting out the startup cost. The process is kept alive as long as you use Gradle, and is terminated after three hours of idle time. Using the daemon is particularly useful when you use Gradle several times in a short time span. You can enable the daemon in the gradle.properties file like this: org.gradle.daemon=true In Android Studio, the Gradle daemon is enabled by default. This means that after the first build from inside the IDE, the next builds are a bit faster. If you build from the command-line interface; however, the Gradle daemon is disabled, unless you enable it in the properties. To speed up the compilation itself, you can tweak parameters on the Java Virtual Machine (JVM). There is a Gradle property called jvmargs that enables you to set different values for the memory allocation pool for the JVM. The two parameters that have a direct influence on your build speed are Xms and Xmx. The Xms parameter is used to set the initial amount of memory to be used, while the Xmx parameter is used to set a maximum. You can manually set these values in the gradle.properties file like this: org.gradle.jvmargs=-Xms256m -Xmx1024m You need to set the desired amount and a unit, which can be k for kilobytes, m for megabytes, and g for gigabytes. By default, the maximum memory allocation (Xmx) is set to 256 MB, and the starting memory allocation (Xms) is not set at all. The optimal settings depend on the capabilities of your computer. The last property you can configure to influence build speed is org.gradle.configureondemand. This property is particularly useful if you have complex projects with several modules, as it tries to limit the time spent in the configuration phase, by skipping modules that are not required for the task that is being executed. If you set this property to true, Gradle will try to figure out which modules have configuration changes and which ones do not, before it runs the configuration phase. This is a feature that will not be very useful if you only have an Android app and a library in your project. If you have a lot of modules that are loosely coupled, though, this feature can save you a lot of build time. System-wide Gradle properties If you want to apply these properties system-wide to all your Gradle-based projects, you can create a gradle.properties file in the .gradle folder in your home directory. On Microsoft Windows, the full path to this directory is %UserProfile%.gradle, on Linux and Mac OS X it is ~/.gradle. It is a good practice to set these properties in your home directory, rather than on the project level. The reason for this is that you usually want to keep memory consumption down on build servers, and the build time is of less importance. Android Studio The Gradle properties you can change to speed up the compilation process are also configurable in the Android Studio settings. To find the compiler settings, open the Settings dialog, and then navigate to Build, Execution, Deployment | Compiler. On that screen, you can find settings for parallel builds, JVM options, configure on demand, and so on. These settings only show up for Gradle-based Android modules. Have a look at the following screenshot: Configuring these settings from Android Studio is easier than configuring them manually in the build configuration file, and the settings dialog makes it easy to find properties that influence the build process. Profiling If you want to find out which parts of the build are slowing the process down, you can profile the entire build process. You can do this by adding the --profile flag whenever you execute a Gradle task. When you provide this flag, Gradle creates a profiling report, which can tell you which parts of the build process are the most time consuming. Once you know where the bottlenecks are, you can make the necessary changes. The report is saved as an HTML file in your module in build/reports/profile. This is the report generated after executing the build task on a multimodule project: The profiling report shows an overview of the time spent in each phase while executing the task. Below that summary is an overview of how much time Gradle spent on the configuration phase for each module. There are two more sections in the report that are not shown in the screenshot. The Dependency Resolution section shows how long it took to resolve dependencies, per module. Lastly, the Task Execution section contains an extremely detailed task execution overview. This overview has the timing for every single task, ordered by execution time from high to low. Jack and Jill If you are willing to use experimental tools, you can enable Jack and Jill to speed up builds. Jack (Java Android Compiler Kit) is a new Android build toolchain that compiles Java source code directly to the Android Dalvik executable (dex) format. It has its own .jack library format and takes care of packaging and shrinking as well. Jill (Jack Intermediate Library Linker) is a tool that can convert .aar and .jar files to .jack libraries. These tools are still quite experimental, but they were made to improve build times and to simplify the Android build process. It is not recommended to start using Jack and Jill for production versions of your projects, but they are made available so that you can try them out. To be able to use Jack and Jill, you need to use build tools version 21.1.1 or higher, and the Android plugin for Gradle version 1.0.0 or higher. Enabling Jack and Jill is as easy as setting one property in the defaultConfig block: android {   buildToolsRevision '22.0.1'   defaultConfig {     useJack = true   }} You can also enable Jack and Jill on a certain build type or product flavor. This way, you can continue using the regular build toolchain, and have an experimental build on the side: android {   productFlavors {       regular {           useJack = false       }        experimental {           useJack = true       }   }} As soon as you set useJack to true, minification and obfuscation will not go through ProGuard anymore, but you can still use the ProGuard rules syntax to specify certain rules and exceptions. Use the same proguardFiles method that we mentioned before, when talking about ProGuard. Summary This article helped us lean different ways to speed up builds; we first saw how we can tweak the settings, configure Gradle and the JVM, we saw how to detect parts that are slowing down the process, and then we learned Jack and Jill tool. Resources for Article: Further resources on this subject: Android Tech Page Android Virtual Device Manager Apache Maven and m2eclipse  Saying Hello to Unity and Android
Read more
  • 0
  • 0
  • 8354

article-image-detecting-touchscreen-gestures
Packt
06 Aug 2015
18 min read
Save for later

Detecting Touchscreen Gestures

Packt
06 Aug 2015
18 min read
In this article by Kyle Mew author of the book, Android 5 Programming by Example, we will learn how to: Add a GestureDetector to a view Add an OnTouchListener and an OnGestureListener Detect and refine fling gestures Use the DDMS Logcat to observe the MotionEvent class Edit the Logcat filter configuration Simplify code with a SimpleOnGestureListener Add a GestureDetector to an Activity Edit the Manifest to control launch behavior Hide UI elements Create a splash screen Lock screen orientation (For more resources related to this topic, see here.) Adding a GestureDetector to a view Together, view.GestureDetector and view.View.OnTouchListener are all that are required to provide our ImageView with gesture functionality. The listener contains an onTouch() callback that relays each MotionEvent to the detector. We are going to program the large ImageView so that it can display a small gallery of related pictures that can be accessed by swiping left or right on the image. There are two steps to this task as, before we implement our gesture detector, we need to provide the data for it to work on. Adding the gallery data As this app is for demonstration and learning purposes, and so we can progress as quickly as possible, we will only provide extra images for one or two of the ancient sites in the project. Here is how it's done: Open the Ancient Britain project. Open the MainData.java file. Add the following arrays: static Integer[] hengeArray = {R.drawable.henge_large, R.drawable.henge_2, R.drawable.henge_3, R.drawable.henge_4}; static Integer[] horseArray = {}; static Integer[] wallArray = {R.drawable.wall_large, R.drawable.wall_2}; static Integer[] skaraArray = {}; static Integer[] towerArray = {}; static Integer[][] galleryArray = {hengeArray, horseArray, wallArray, skaraArray, towerArray}; Either download the project files from the Packt website or find four of your own images (around 640 x 480 px). Name them henge_2, henge_3, henge_4, and wall_2 and place them in your res/drawable directory. This is all very straightforward, and the code that will accompany it allows you to have individual arrays of any length. This is all we need to add to our gallery data. Now, we need to code our GestureDetector and OnTouchListener. Adding the GestureDetector Along with the OnTouchListener that we will define for our ImageView, the GestureDetector has its own listeners. Here we will use GestureDetector.OnGestureListener to detect a fling gesture and collect the MotionEvent that describe it. Follow these steps to program your ImageView to respond to fling gestures: Open the DetailActivity.java file. Declare the following class fields: private static final int MIN_DISTANCE = 150; private static final int OFF_PATH = 100; private static final int VELOCITY_THRESHOLD = 75; private GestureDetector detector; View.OnTouchListener listener; private int ImageIndex; In the onCreate() method assigns both the detector and listener like this: detector = new GestureDetector(this, new GalleryGestureDetector()); listener = new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { return detector.onTouchEvent(event); } }; Beneath this, add the following line: ImageIndex = 0; Beneath the line detailImage = (ImageView) findViewById(R.id.detail_image);, add the following line: detailImage.setOnTouchListener(listener); Create the following inner class: class GalleryGestureDetector implements GestureDetector.OnGestureListener { } Before dealing with the errors this generates, add the following field to the class: private int item; { item = MainActivity.currentItem; } Click anywhere on the line registering the error and press Alt + Enter. Then select Implement Methods, making sure that you have the Copy JavaDoc and Insert @Override boxes checked. Complete the onDown() method like this: @Override public boolean onDown(MotionEvent e) { return true; } Fill in the onShowPress() method: @Override public void onShowPress(MotionEvent e) { detailImage.setElevation(4); } Then fill in the onFling() method: @Override public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) { if (Math.abs(event1.getY() - event2.getY()) > OFF_PATH) return false; if (MainData.galleryArray[item].length != 0) { // Swipe left if (event1.getX() - event2.getX() > MIN_DISTANCE && Math.abs(velocityX) > VELOCITY_THRESHOLD) { ImageIndex++; if (ImageIndex == MainData.galleryArray[item].length) ImageIndex = 0; detailImage.setImageResource(MainData .galleryArray[item][ImageIndex]); } else { // Swipe right if (event2.getX() - event1.getX() > MIN_DISTANCE && Math.abs(velocityX) > VELOCITY_THRESHOLD) { ImageIndex--; if (ImageIndex < 0) ImageIndex = MainData.galleryArray[item].length - 1; detailImage.setImageResource(MainData .galleryArray[item][ImageIndex]); } } } detailImage.setElevation(0); return true; } Test the project on an emulator or handset. The process of gesture detection in the preceding code begins when the OnTouchListener listener's onTouch() method is called. It then passes that MotionEvent to our gesture detector class, GalleryGestureDetector, which monitors motion events, sometimes stringing them together and timing them until one of the recognized gestures is detected. At this point, we can enter our own code to control how our app responds as we did here with the onDown(), onShowPress(), and onFling() callbacks. It is worth taking a quick look at these methods in turn. It may seem, at the first glance, that the onDown() method is redundant; after all, it's the fling gesture that we are trying to catch. In fact, overriding the onDown() method and returning true from it is essential in all gesture detections as all the gestures begin with an onDown() event. The purpose of the onShowPress() method may also appear unclear as it seems to do a little more than onDown(). As the JavaDoc states, this method is handy for adding some form of feedback to the user, acknowledging that their touch has been received. The Material Design guidelines strongly recommend such feedback and here we have raised the view's elevation slightly. Without including our own code, the onFling() method will recognize almost any movement across the bounding view that ends in the user's finger being raised, regardless of direction or speed. We do not want very small or very slow motions to result in action; furthermore, we want to be able to differentiate between vertical and horizontal movement as well as left and right swipes. The MIN_DISTANCE and OFF_PATH constants are in pixels and VELOCITY_THRESHOLD is in pixels per second. These values will need tweaking according to the target device and personal preference. The first MotionEvent argument in onFling() refers to the preceding onDown() event and, like any MotionEvent, its coordinates are available through its getX() and getY() methods. The MotionEvent class contains dozens of useful classes for querying various event properties—for example, getDownTime(), which returns the time in milliseconds since the current onDown() event. In this example, we used GestureDetector.OnGestureListener to capture our gesture. However, the GestureDetector has three such nested classes, the other two being SimpleOnGestureListener and OnDoubleTapListener. SimpleOnGestureListener provides a more convenient way to detect gestures as we only need to implement those methods that relate to the gestures we are interested in capturing. We will shortly edit our Activity so that it implements the SimpleOnGestureListener instead, allowing us to tidy our code and remove the four callbacks that we do not need. The reason for taking this detour, rather than applying the simple listener to begin with, was to get to see all of the gestures available to us through a gesture listener and demonstrate how useful JavaDoc comments can be, particularly if we are new to the framework. For example, take a look at the following screenshot: Another very handy tool is the Dalvik Debug Monitor Server (DDMS), which allows us to see what is going on inside our apps while they are running. The workings of our gesture listener are a good place to do this as most of its methods operate invisibly. Viewing gesture activity with DDMS To view the workings of our OnGestureListener with DDMS, we need to first create a tag to identify our messages and then a filter to view them. The following steps demonstrate how to do this: Open the DetailActivity.java file. Declare the following constant: private static final String DEBUG_TAG = "tag"; Add the following line inside the onDown() method: Log.d(DEBUG_TAG, "onDown"); Add the line Log.d(DEBUG_TAG, "onShowPress"); to the onShowPress() method and do the same for each of our OnGestureDetector methods. Add the following lines to the appropriate clauses in onFling(): Log.d(DEBUG_TAG, "left"); Log.d(DEBUG_TAG, "right"); Open the Android DDMS pane from the Android tab at the bottom of the window or by pressing Alt + 6. If logcat is not visible, it can be opened with the icon to the right of the top-right drop-down menu. Click on this drop-down menu and select Edit Filter Configuration. Complete the dialog as shown in the following screenshot: You can now run the project on a handset or emulator and view, in the Logcat, which gestures are being triggered and how. Your output should resemble the one here: 02-17 14:39:00.990 1430- 1430/com.example.kyle.ancientbritain D/tag﹕ onDown 02-17 14:39:01.039 1430- 1430/com.example.kyle.ancientbritain D/tag﹕ onSingleTapUp 02-17 14:39:03.503 1430- 1430/com.example.kyle.ancientbritain D/tag﹕ onDown 02-17 14:39:03.601 1430- 1430/com.example.kyle.ancientbritain D/tag﹕ onShowPress 02-17 14:39:04.101 1430- 1430/com.example.kyle.ancientbritain D/tag﹕ onLongPress 02-17 14:39:10.484 1430- 1430/com.example.kyle.ancientbritain D/tag﹕ onDown 02-17 14:39:10.541 1430- 1430/com.example.kyle.ancientbritain D/tag﹕ onScroll 02-17 14:39:11.091 1430- 1430/com.example.kyle.ancientbritain D/tag﹕ onScroll 02-17 14:39:11.232 1430- 1430/com.example.kyle.ancientbritain D/tag﹕ onFling 02-17 14:39:11.680 1430- 1430/com.example.kyle.ancientbritain D/tag﹕ right 02-17 14:39:01.039   1430- 1430/com.example.kyle.ancientbritain D/tag﹕ onSingleTapUp DDMS is an invaluable tool when it comes to debugging our apps and seeing what is going on beneath the hood. Once a Log Tag has been defined in the code, we can then create a filter for it so that we see only the messages we are interested in. The Log class contains several methods to report information based on its level of importance. We used Log.d, which stands for debug. All these methods work with the same two parameters: Log.[method](String tag, String message). The full list of these methods is as follows: Log.v: Verbose Log.d: Debug Log.i: Information Log.w: Warning Log.e: Error Log.wtf: Unexpected error It is worth noting that most debug messages will be ignored during the packaging for distribution except for the verbose messages; thus, it is essential to remove them before your final build. Having seen a little more of the inner workings of our gesture detector and listener, we can now strip our code of unused methods by implementing GestureDetector.SimpleOnGestureListener. Implementing a SimpleOnGestureListener It is very simple to convert our gesture detector from one class of listener to another. All we need to do is change the class declaration and delete the unwanted methods. To do this, perform the following steps: Open the DetailActivity file. Change the class declaration for our gesture detector class to the following: class GalleryGestureDetector extends GestureDetector.SimpleOnGestureListener { Delete the onShowPress(), onSingleTapUp(), onScroll(), and onLongPress() methods. This is all you need to do to switch to the SimpleOnGestureListener. We have now successfully constructed and edited a gesture detector to allow the user to browse a series of images. You will have noticed that there is no onDoubleTap() method in the gesture listener. Double-taps can, in fact, be handled with the third GestureDetector listener, OnDoubleTapListener, which operates in a very similar way to the other two. However, Google, in its UI guidelines, recommends that a long press should be used instead, whenever possible. Before moving on to multitouch events, we will take a look at how to attach a GestureDetector listener to an entire Activity by adding a splash screen to our project. In the process, we will also see how to create a Full-Screen Activity and how to edit the Maniftest file so that our app launches with the splash screen. Adding a GestureDetector to an Activity The method we have employed so far allows us to attach a GestureDetector listener to any view or views and this, of course, applies to ViewGroups such as Layouts. There are times when we may want to detect gestures to be applied to the whole screen. For this purpose, we will create a splash screen that can be dismissed with a long press. There are two things we need to do before implementing the gesture detector: creating a layout and editing the Manifest file so that the app launches with our splash screen. Designing the splash screen layout The main difference between processing gestures for a whole Activity and an individual widget, is that we do not need an OnTouchListener as we can override the Activity's own onTouchEvent(). Here is how it is done: Create a new Blank Activity from the Project Explorer context menu called SplashActivity.java. The Activity wizard should have created an associated XML layout called activity_splash.xml. Open this and view it using the Text tab. Remove all the padding properties from the root layout so that it looks similar to this: <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.kyle.ancientbritain .SplashActivity"> Here we will need an image to act as the background for our splash screen. If you have not downloaded the project files from the Packt website, find an image, roughly of the size and aspect of your target device's screen, upload it to the project drawable folder, and call it splash. The file I used is 480 x 800 px. Remove the TextView that the wizard placed inside the layout and replace it with this ImageView: <ImageView android:id="@+id/splash_image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/splash"/> Create a TextView beneath this, such as the following: <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:layout_marginBottom="40dp" android:gravity="center_horizontal" android:textAppearance="?android:attr/ textAppearanceLarge" android:textColor="#fffcfcbd"/> Add the following text property: android:text="Welcome to <b>Ancient Britain</b>npress and hold nanywhere on the screennto start" To save time adding string resources to the strings.xml file, enter a hardcoded string such as the preceding one and heed the warning from the editor to have the string extracted for you like this: There is nothing in this layout that we have not encountered before. We removed all the padding so that our splash image will fill the layout; however, you will see from the preview that this does not appear to be the case. We will deal with this next in our Java code, but we need to edit our Manifest first so that the app gets launched with our SplashActivity. Editing the Manifest It is very simple to configure the AndroidManifest file so that an app will get launched with whichever Activity we choose; the way it does so is with an intent. While we are editing the Manifest, we will also configure the display to fill the screen. Simply follow these steps: Open the res/values-v21/styles.xml file and add the following style: <style name="SplashTheme" parent="android:Theme.Material. NoActionBar.Fullscreen"> </style> Open the AndroidManifest.xml file. Cut-and-paste the <intent-filter> element from MainActivity to SplashActivity. Include the following properties so that the entire <activity> node looks similar to this: <activity android:name=".SplashActivity" android:theme="@style/SplashTheme" android:screenOrientation="portrait" android:configChanges="orientation|screenSize" android:label="Old UK" > <intent-filter> <action android_name="android.intent.action.MAIN" /> <category android_name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> We have encountered themes and styles before and, here, we took advantage of a built-in theme designed for full screen activities. In many cases, we might have designed a landscape layout here but, as is often the case with splash screens, we locked the orientation with the android:screenOrientation property. The android:configChanges line is not actually needed here, but is included as it is useful to know about it. Configuring any attribute such as this prevents the system from automatically reloading the Activity whenever the device is rotated or the screen size changed. Instead of the Activity restarting, the onConfigurationChanged() method is called. This was not needed here as the screen size and orientation were taken care of in the previous lines of code and this line was only included as a point of interest. Finally, we changed the value of android:label. You may have noticed that, depending on the screen size of the device you are using, the name of our app is not displayed in full on the home screen or apps drawer. In such cases, when you want to use a shortened name for your app, it can be inserted here. With everything else in place, we can get on with adding our gesture detector. This is not dissimilar to the way we did this before but, this time, we will apply the detector to the whole screen and will be listening for a long press, rather than a fling. Adding the GestureDetector Along with implementing a gesture detector for the entire Activity here, we will also take the final step in configuring our splash screen so that the image fills the screen, but maintains its aspect ratio. Follow these steps to complete the app splash screen. Open the SplashActivity file. Declare a GestureDetector as we did in the earlier exercise: private GestureDetector detector; In the onCreate() method, assign and configure our splash image and gesture detector like this: ImageView imageView = (ImageView) findViewById(R.id.splash_image); imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); detector = new GestureDetector(this, new SplashListener()); Now, override the Activity's onTouchEvent() like this: @Override public boolean onTouchEvent(MotionEvent event) { this.detector.onTouchEvent(event); return super.onTouchEvent(event); } Create the following SimpleOnGestureListener class: private class SplashListener extends GestureDetector. SimpleOnGestureListener { @Override public boolean onDown(MotionEvent e) { return true; } @Override public void onLongPress(MotionEvent e) { startActivity(new Intent(getApplicationContext(), MainActivity.class)); } } Build and run the app on your phone or an emulator. The way a gesture detector is implemented across an entire Activity should be familiar by this point, as should the capturing of the long press event. The ImageView.setScaleType(ImageView.ScaleType) method is essential here; it is a very useful method in general. The CENTER_CROP constant scales the image to fill the view while maintaining the aspect ratio, cropping the edges when necessary. There are several similar ScaleTypes, such as CENTER_INSIDE, which scales the image to the maximum size possible without cropping it, and CENTER, which does not scale the image at all. The beauty of CENTER_CROP is that it means that we don't have to design a separate image for every possible aspect ratio on the numerous devices our apps will end up running on. Provided that we make allowances for very wide or very narrow screens by not including essential information too close to the edges, we only need to provide a handful of images of varying pixel densities to maintain the image quality on large, high-resolution devices. The scale type of ImageView can be set from within XML with android:scaleType="centerCrop", for example. You may have wondered why we did not use the built-in Full-Screen Activity from the wizard; we could easily have done so. The template code the wizard creates for a Full-Screen Activity provides far more features than we needed for this exercise. Nevertheless, the template is worth taking a look at, especially if you want a fullscreen that brings the status bar and other components into view when the user interacts with the Activity. That brings us to the end of this article. Not only have we seen how to make our apps interact with touch events and gestures, but also how to send debug messages to the IDE and make a Full-Screen Activity. Summary We began this article by adding a GestureDetector to our project. We then edited it so that we could filter out meaningful touch events (swipe right and left, in this case). We went on to see how the SimpleOnGestureListener can save us a lot of time when we are only interested in catching a subset of the recognized gestures. We also saw how to use DDMS to pass debug messages during runtime and how, through a combination of XML and Java, the status and action bars can be hidden and the entire screen be filled with a single view or view group. Resources for Article: Further resources on this subject: Speeding up Gradle builds for Android [Article] Saying Hello to Unity and Android [Article] Testing with the Android SDK [Article]
Read more
  • 0
  • 0
  • 7934
article-image-introducing-android-platform
Packt
12 Sep 2013
9 min read
Save for later

Introducing an Android platform

Packt
12 Sep 2013
9 min read
(For more resources related to this topic, see here.) Introducing an Android app Mobile software application that runs on Android is an Android app. The apps use the extension of .apk as the installer file extension. There are several popular examples of mobile apps, such as Foursquare, Angry Birds, and Fruit Ninja. Primarily in an Eclipse environment, we use Java, which is then compiled into Dalvik bytecode (not the ordinary Java bytecode). Android provides Dalvik virtual machine (DVM) inside Android (not Java virtual machine JVM). Dalvik VM does not ally with Java SE and Java ME libraries, and is built on an Apache Harmony java implementation. What is Dalvik virtual machine? Dalvik VM is a register-based architecture, authored by Dan Bornstein. It is being optimized for low memory requirements, and the virtual machine was slimmed down to use less space and less power consumption. Preparing for Android development Eclipse ADT In this part of the article, we will see how to install the development environment for Android on Eclipse Juno (4.2). Eclipse is a major IDE for Android development. We need to install an Eclipse extension ADT Android Development Toolkit (ADT) for development of the Android application. Debugging an Android project It is advisable to use the Log class for this purpose, the reason being we can filter, print different colors, and define log types. This could be one of the ways of debugging your program, by displaying variables value or parameters. To use Log, import android.util.Log, and use one the following methods to print messages to LogCat: v(String, String) (verbose) d(String, String) (debug) i(String, String) (information) w(String, String) (warning) e(String, String) (error) LogCat is used to view the internal log of the Android system. It is useful to trace any activity happening inside the device or emulator through the Android Debug Bridge (ADB). The Android project structure The following table illustrates the brief description of the important folders and files available in an Android project: Folder Functions /src The Java codes are placed in this folder. /gen It is generated automatically. /assets You can put your fonts, videos, and sounds here. It is more like a filesystem, and can also place CSS, JavaScript files, and so on. /libs It is an external library (normally in JAR). /res It contains images, layout, and global variables. /drawable-xhdpi It is used for extra high specification devices (for example, Tablet, Galaxy SIII, HTC One X). /drawable-hdpi  It is used for high specification phones (for example, SGSI, SGSII) /drawable-mdpi It is used for medium specification phones (for example, Galaxy W and HTC Desire). /drawable-ldpi  It is used for low specification phones (for example: Galaxy Y and HTC WildFire). /layout  It includes all the XML file for the screen(s) layout. /menu XML files for screen menu. /values It includes global constants. /values-v11 These are template styles definitions for devices with Honeycomb (Android API level 11). /values-v14 These are template styles definitions for devices with ICS (Android API level 14). AndroidManifest.xml This is one of important files to define the apps. This is the first file located by the Android OS in order to run the app. It contains the app's properties, activity declarations, and list of permissions.   Dalvik Debug Monitor Server (DDMS) DDMS is a must have tool to view the emulator/device activities. To access DDMS in the Eclipse, navigate to Windows | Open Perspective | Other, and then choose DDMS. By default it is available in the Android SDK (it's inside the folder android-sdk/tools by the file ddms). From this perspective the following aspects are available: Devices: The list of the devices and AVD that are connected to ADB Emulator control: It helps to carry out device functions LogCat: It views real-time system log messages Threads: It gives an idea of currently running threads within a VM Heap: It shows heap usage by application Allocation tracker: It provides information on memory allocation of objects File explorer: It explores the device filesystem Creating a new Android project using Eclipse ADT To create a new Android project in Eclipse, navigate to File | New | Project. A new project window will appear, from there choose Android | Android Application Project from the list. Then click on the Next button. Application Name: This is the name of your application, it will appear side-by-side to the launcher icon. Choose a project name that relevant to your application. Project Name: This is typically similar to your application name. Avoid having the same name with existing projects in Eclipse, it is not permitted. Package Name: This is the package name of the application. It will act as an ID in the Google Play app store if we wish to publish. Typically it will be the reverse of your domain name if we have one (since this is unique) followed by the application name, and a valid Java package name else we can have anything now and refactor it before publishing. Running the application on an Android device To run and deploy on real device, first install the driver of the device. This varies as per device model and manufacturer. These are a few links you could refer to: For Google Android devices refer to http://developer.android.com/sdk/win-usb.html. For others refer to http://www.teamandroid.com/download-android-usb-drivers/. Make sure the Android phone is connected to the computer through the USB cable. To check whether the phone is properly connected to your PC and in debug mode, please switch to the DDMS perspective. Adding multiple activity in Android application This exercise is to add an information screen on the SimpleNumb3r5 app. The information regarding the developer, e-mail, Facebook fan page, and other information is displayed. Since the screen contains a lot of text information including several pictures, so we make use of an HTML page as our approach here: Create an activity class to handle the new screen. Open the src folder, right-click on the package name (net.kerul.SimpleNumb3r5), and choose New | Other... from the selections, choose to add a new Android activity, and click on the Next button. Then, choose a blank activity and click on Next. Set the activity name as Info, and the wizard will suggest the screen layout as info_activity. Click on the Finish button. Adding the RadioGroup or RadioButton controls Android SDK provides two types of radio controls to be used in conjunction, where only one control can be chosen at a given time. RadioGroup (Android widget RadioGroup) is used to encapsulate a set of RadioButton controls for this purpose. Defining the preference screen Preferences are an important aspect of the Android applications. It allows users to have the choice to modify and personalize it. Preferences can be set in two ways: first method is to create the preferences.xml file in the res/xml directory, and second method is to set the preferences from the code. We will use the former also the easier one, by creating the preferences.xml file. Usually, there are five different preference views as listed in the following table: Views Description CheckBoxPreference It is a simple checkbox which returns true/false ListPreference It shows RadioGroup, where only 1 item can be selected EditTextPreference It shows dialog box to edit TextView, and returns String RingTonePreference It is a radioGroup that shows ringtone PreferenceCategory It is a category with preferences Fragment A fragment is an independent component that can be connected to an Activity or simply is subactivity. Typically it defines a part of UI but can also exist with no user interface, that is, headless. An instance of fragment must exist within an activity. Fragments ease the reuse of components for different layouts. Fragments are the way to support UI variances across different types of screens. The most popular use is of building single pane layouts for phone and multipane layouts for tablets (large screens). Adding an external library Android project – AdMob An Android application cannot achieve everything on its own, it will always need the company of external jars/libraries to achieve different goals and serve various purposes. Almost every free Android application published on store has advertisement embedded in it, which makes use of external component to achieve it. Incorporating advertisement in the Android application is a vital aspect of today's application development. In this article, we will continue on our DistanceConverter application, and make use of the external library, AdMob to incorporate advertisement in our application. Adding the AdMob SDK to the project Let's extract the previously downloaded AdMob SDK zip file, and we should get the folder GoogleAdMobAdsSdkAndroid-6.*.*, under that folder there is GoogleAdMobAdsSdk-6.x.x.jar. You should copy this JAR file in the libs folder of the project. Signing and distributing APK The Android package (APK), in simple terms is similar to the runnable JAR or executable file (on Windows OS) which consists of everything that is needed to run the application. The Android ecosystem uses a virtual machine, that is, Dalvik virtual machine (DVM) to run the Java applications. Dalvik uses its own bytecode which is quite different from the Java bytecode. Generating a private key An android application must be signed with our own private key. It identifies a person, corporate, or entity associated with the application. This can be generated using the program keytool from the Java SDK. The following command is used for generating the key: keytool -genkey -v -keystore <filename>.keystore -alias <key-name> -keyalg RSA -keysize 2048 -validity 10000 We can use different key for each published application, and specify different name to identify it. Also, Google expects validity of at least 25 years or more. A very important thing to consider is to keep back up and securely store key, because once it is compromised it impossible to update an already published application. Publishing to Google Play Publishing at Google Play is very simple and involves register for Google play. You just have to visit and register it at https://play.google.com/. It requires $25 USD to register, and is fairly straight and can take a few days until you get the final access. Summary In this article, we learned how to install the Eclipse Juno (the IDE), the Android SDK and the testing platform. Also, we learned about the fragment and its usage, and used it to have different layouts for landscape mode for our application DistanceConverter. We also learned about handling different screen types and persisting state during screen mode changes. Resources for Article: Further resources on this subject: Installing Alfresco Software Development Kit (SDK) [Article] JBoss AS plug-in and the Eclipse Web Tools Platform [Article] Creating a pop-up menu [Article]
Read more
  • 0
  • 0
  • 7809

article-image-testing-android-sdk
Packt
26 Mar 2015
25 min read
Save for later

Testing with the Android SDK

Packt
26 Mar 2015
25 min read
In this article by the author, Paul Blundell, of the book, Learning Android Application Testing, we learn to start digging a bit deeper to recognize the building blocks available to create more useful tests. We will be covering the following topics: Common assertions View assertions Other assertion types Helpers to test User Interfaces Mock objects Instrumentation TestCase class hierarchies Using external libraries We will be analyzing these components and showing examples of their use when applicable. The examples in this article are intentionally split from the original Android project that contains them. This is done to let you concentrate and focus only on the subject being presented, though the complete examples in a single project can be downloaded as explained later. Right now, we are interested in the trees and not the forest. Along with the examples presented, we will be identifying reusable common patterns that will help you in the creation of tests for your own projects. (For more resources related to this topic, see here.) The demonstration application A very simple application has been created to demonstrate the use of some of the tests in this article. The source for the application can be downloaded from XXXXXXXXXXXXX. The following screenshot shows this application running: When reading the explanation of the tests in this article, at any point, you can refer to the demo application that is provided in order to see the test in action. The previous simple application has a clickable link, text input, click on a button and a defined layout UI, we can test these one by one. Assertions in depth Assertions are methods that check for a condition that can be evaluated. If the condition is not met, the assertion method will throw an exception, thereby aborting the execution of the test. The JUnit API includes the class Assert. This is the base class of all the TestCase classes that hold several assertion methods useful for writing tests. These inherited methods test for a variety of conditions and are overloaded to support different parameter types. They can be grouped together in the following different sets, depending on the condition checked, for example: assertEquals assertTrue assertFalse assertNull assertNotNull assertSame assertNotSame fail The condition tested is pretty obvious and is easily identifiable by the method name. Perhaps the ones that deserve some attention are assertEquals() and assertSame(). The former, when used on objects, asserts that both objects passed as parameters are equally calling the objects' equals() method. The latter asserts that both objects refer to the same object. If, in some case, equals() is not implemented by the class, then assertEquals() and assertSame() will do the same thing. When one of these assertions fails inside a test, an AssertionFailedException is thrown, and this indicates that the test has failed. Occasionally, during the development process, you might need to create a test that you are not implementing at that precise time. However, you want to flag that the creation of the test was postponed. In such cases, you can use the fail() method, which always fails and uses a custom message that indicates the condition: public void testNotImplementedYet() {    fail("Not implemented yet"); } Still, there is another common use for fail() that is worth mentioning. If we need to test whether a method throws an exception, we can surround the code with a try-catch block and force a fail if the exception was not thrown. For example: public void testShouldThrowException() {    try {    MyFirstProjectActivity.methodThatShouldThrowException();      fail("Exception was not thrown");    } catch ( Exception ex ) {      // do nothing    } } JUnit4 has the annotation @Test(expected=Exception.class), and this supersedes the need for using fail() when testing exceptions. With this annotation, the test will only pass if the expected exception is thrown. Custom message It is worth knowing that all assert methods provide an overloaded version including a custom String message. Should the assertion fail, this custom message will be printed by the test runner, instead of a default message. The premise behind this is that, sometimes, the generic error message does not reveal enough details, and it is not obvious how the test failed. This custom message can be extremely useful to easily identify the failure once you are looking at the test report, so it's highly recommended as a best practice to use this version. The following is an example of a simple test that uses this recommendation: public void testMax() { int a = 10; int b = 20;   int actual = Math.max(a, b);   String failMsg = "Expected: " + b + " but was: " + actual; assertEquals(failMsg, b, actual); } In the preceding example, we can see another practice that would help you organize and understand your tests easily. This is the use of explicit names for variables that hold the actual values. There are other libraries available that have better default error messages and also a more fluid interface for testing. One of these that is worth looking at is Fest (https://code.google.com/p/fest/). Static imports Though basic assertion methods are inherited from the Assert base class, some other assertions need specific imports. To improve the readability of your tests, there is a pattern to statically import the assert methods from the corresponding classes. Using this pattern instead of having: public void testAlignment() { int margin = 0;    ... android.test.ViewAsserts.assertRightAligned (errorMsg, editText, margin); } We can simplify it by adding the static import: import static android.test.ViewAsserts.assertRightAligned; public void testAlignment() {    int margin = 0;    assertRightAligned(errorMsg, editText, margin); } View assertions The assertions introduced earlier handle a variety of types as parameters, but they are only intended to test simple conditions or simple objects. For example, we have asertEquals(short expected, short actual) to test short values, assertEquals(int expected, int actual) to test integer values, assertEquals(Object expected, Object expected) to test any Object instance, and so on. Usually, while testing user interfaces in Android, you will face the problem of more sophisticated methods, which are mainly related with Views. In this respect, Android provides a class with plenty of assertions in android.test.ViewAsserts (see http://developer.android.com/reference/android/test/ViewAsserts.html for more details), which test relationships between Views and their absolute and relative positions on the screen. These methods are also overloaded to provide different conditions. Among the assertions, we can find the following: assertBaselineAligned: This asserts that two Views are aligned on their baseline; that is, their baselines are on the same y location. assertBottomAligned: This asserts that two views are bottom aligned; that is, their bottom edges are on the same y location. assertGroupContains: This asserts that the specified group contains a specific child once and only once. assertGroupIntegrity: This asserts the specified group's integrity. The child count should be >= 0 and each child should be non-null. assertGroupNotContains: This asserts that the specified group does not contain a specific child. assertHasScreenCoordinates: This asserts that a View has a particular x and y position on the visible screen. assertHorizontalCenterAligned: This asserts that the test View is horizontally center aligned with respect to the reference view. assertLeftAligned: This asserts that two Views are left aligned; that is, their left edges are on the same x location. An optional margin can also be provided. assertOffScreenAbove: This asserts that the specified view is above the visible screen. assertOffScreenBelow: This asserts that the specified view is below the visible screen. assertOnScreen: This asserts that a View is on the screen. assertRightAligned: This asserts that two Views are right-aligned; that is, their right edges are on the same x location. An optional margin can also be specified. assertTopAligned: This asserts that two Views are top aligned; that is, their top edges are on the same y location. An optional margin can also be specified. assertVerticalCenterAligned: This asserts that the test View is vertically center-aligned with respect to the reference View. The following example shows how you can use ViewAssertions to test the user interface layout: public void testUserInterfaceLayout() {    int margin = 0;    View origin = mActivity.getWindow().getDecorView();    assertOnScreen(origin, editText);    assertOnScreen(origin, button);    assertRightAligned(editText, button, margin); } The assertOnScreen method uses an origin to start looking for the requested Views. In this case, we are using the top-level window decor View. If, for some reason, you don't need to go that high in the hierarchy, or if this approach is not suitable for your test, you may use another root View in the hierarchy, for example View.getRootView(), which, in our concrete example, would be editText.getRootView(). Even more assertions If the assertions that are reviewed previously do not seem to be enough for your tests' needs, there is still another class included in the Android framework that covers other cases. This class is MoreAsserts (http://developer.android.com/reference/android/test/MoreAsserts.html). These methods are also overloaded to support different parameter types. Among the assertions, we can find the following: assertAssignableFrom: This asserts that an object is assignable to a class. assertContainsRegex: This asserts that an expected Regex matches any substring of the specified String. It fails with the specified message if it does not. assertContainsInAnyOrder: This asserts that the specified Iterable contains precisely the elements expected, but in any order. assertContainsInOrder: This asserts that the specified Iterable contains precisely the elements expected, but in the same order. assertEmpty: This asserts that an Iterable is empty. assertEquals: This is for some Collections not covered in JUnit asserts. assertMatchesRegex: This asserts that the specified Regex exactly matches the String and fails with the provided message if it does not. assertNotContainsRegex: This asserts that the specified Regex does not match any substring of the specified String, and fails with the provided message if it does. assertNotEmpty: This asserts that some Collections not covered in JUnit asserts are not empty. assertNotMatchesRegex: This asserts that the specified Regex does not exactly match the specified String, and fails with the provided message if it does. checkEqualsAndHashCodeMethods: This is a utility used to test the equals() and hashCode() results at once. This tests whether equals() that is applied to both objects matches the specified result. The following test checks for an error during the invocation of the capitalization method called via a click on the UI button: @UiThreadTest public void testNoErrorInCapitalization() { String msg = "capitalize this text"; editText.setText(msg);   button.performClick();   String actual = editText.getText().toString(); String notExpectedRegexp = "(?i:ERROR)"; String errorMsg = "Capitalization error for " + actual; assertNotContainsRegex(errorMsg, notExpectedRegexp, actual); } If you are not familiar with regular expressions, invest some time and visit http://developer.android.com/reference/java/util/regex/package-summary.html because it will be worth it! In this particular case, we are looking for the word ERROR contained in the result with a case-insensitive match (setting the flag i for this purpose). That is, if for some reason, capitalization doesn't work in our application, and it contains an error message, we can detect this condition with the assertion. Note that because this is a test that modifies the user interface, we must annotate it with @UiThreadTest; otherwise, it won't be able to alter the UI from a different thread, and we will receive the following exception: INFO/TestRunner(610): ----- begin exception ----- INFO/TestRunner(610): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. INFO/TestRunner(610):     at android.view.ViewRoot.checkThread(ViewRoot.java:2932) [...] INFO/TestRunner(610):     at android.app. Instrumentation$InstrumentationThread.run(Instrumentation.java:1447) INFO/TestRunner(610): ----- end exception ----- The TouchUtils class Sometimes, when testing UIs, it is helpful to simulate different kinds of touch events. These touch events can be generated in many different ways, but probably android.test.TouchUtils is the simplest to use. This class provides reusable methods to generate touch events in test cases that are derived from InstrumentationTestCase. The featured methods allow a simulated interaction with the UI under test. The TouchUtils class provides the infrastructure to inject the events using the correct UI or main thread, so no special handling is needed, and you don't need to annotate the test using @UIThreadTest. TouchUtils supports the following: Clicking on a View and releasing it Tapping on a View (touching it and quickly releasing) Long-clicking on a View Dragging the screen Dragging Views The following test represents a typical usage of TouchUtils:    public void testListScrolling() {        listView.scrollTo(0, 0);          TouchUtils.dragQuarterScreenUp(this, activity);        int actualItemPosition = listView.getFirstVisiblePosition();          assertTrue("Wrong position", actualItemPosition > 0);    } This test does the following: Repositions the list at the beginning to start from a known condition Scrolls the list Checks for the first visible position to see that it was correctly scrolled Even the most complex UIs can be tested in that way, and it would help you detect a variety of conditions that could potentially affect the user experience. Mock objects We have seen the mock objects provided by the Android testing framework, and evaluated the concerns about not using real objects to isolate our tests from the surrounding environment. Martin Fowler calls these two styles the classical and mockist Test-driven Development dichotomy in his great article Mocks aren't stubs, which can be read online at http://www.martinfowler.com/articles/mocksArentStubs.html. Independent of this discussion, we are introducing mock objects as one of the available building blocks because, sometimes, using mock objects in our tests is recommended, desirable, useful, or even unavoidable. The Android SDK provides the following classes in the subpackage android.test.mock to help us: MockApplication: This is a mock implementation of the Application class. All methods are non-functional and throw UnsupportedOperationException. MockContentProvider: This is a mock implementation of ContentProvider. All methods are non-functional and throw UnsupportedOperationException. MockContentResolver: This is a mock implementation of the ContentResolver class that isolates the test code from the real content system. All methods are non-functional and throw UnsupportedOperationException. MockContext: This is a mock context class, and this can be used to inject other dependencies. All methods are non-functional and throw UnsupportedOperationException. MockCursor: This is a mock Cursor class that isolates the test code from real Cursor implementation. All methods are non-functional and throw UnsupportedOperationException. MockDialogInterface: This is a mock implementation of the DialogInterface class. All methods are non-functional and throw UnsupportedOperationException. MockPackageManager: This is a mock implementation of the PackageManager class. All methods are non-functional and throw UnsupportedOperationException. MockResources: This is a mock Resources class. All of these classes have non-functional methods that throw UnsupportedOperationException when used. If you need to use some of these methods, or if you detect that your test is failing with this Exception, you should extend one of these base classes and provide the required functionality. MockContext overview This mock can be used to inject other dependencies, mocks, or monitors into the classes under test. Extend this class to provide your desired behavior, overriding the correspondent methods. The Android SDK provides some prebuilt mock Context objects, each of which has a separate use case. The IsolatedContext class In your tests, you might find the need to isolate the Activity under test from other Android components to prevent unwanted interactions. This can be a complete isolation, but sometimes, this isolation avoids interacting with other components, and for your Activity to still run correctly, some connection with the system is required. For those cases, the Android SDK provides android.test.IsolatedContext, a mock Context that not only prevents interaction with most of the underlying system but also satisfies the needs of interacting with other packages or components such as Services or ContentProviders. Alternate route to file and database operations In some cases, all we need is to be able to provide an alternate route to the file and database operations. For example, if we are testing the application on a real device, we perhaps don't want to affect the existing database but use our own testing data. Such cases can take advantage of another class that is not part of the android.test.mock subpackage but is part of android.test instead, that is, RenamingDelegatingContext. This class lets us alter operations on files and databases by having a prefix that is specified in the constructor. All other operations are delegated to the delegating Context that you must specify in the constructor too. Suppose our Activity under test uses a database we want to control, probably introducing specialized content or fixture data to drive our tests, and we don't want to use the real files. In this case, we create a RenamingDelegatingContext class that specifies a prefix, and our unchanged Activity will use this prefix to create any files. For example, if our Activity tries to access a file named birthdays.txt, and we provide a RenamingDelegatingContext class that specifies the prefix test, then this same Activity will access the file testbirthdays.txt instead when it is being tested. The MockContentResolver class The MockContentResolver class implements all methods in a non-functional way and throws the exception UnsupportedOperationException if you attempt to use them. The reason for this class is to isolate tests from the real content. Let's say your application uses a ContentProvider class to feed your Activity information. You can create unit tests for this ContentProvider using ProviderTestCase2, which we will be analyzing shortly, but when we try to produce functional or integration tests for the Activity against ContentProvider, it's not so evident as to what test case to use. The most obvious choice is ActivityInstrumentationTestCase2, mainly if your functional tests simulate user experience because you might need the sendKeys() method or similar methods, which are readily available on these tests. The first problem you might encounter then is that it's unclear as to where to inject a MockContentResolver in your test to be able to use test data with your ContentProvider. There's no way to inject a MockContext either. The TestCase base class This is the base class of all other test cases in the JUnit framework. It implements the basic methods that we were analyzing in the previous examples (setUp()). The TestCase class also implements the junit.framework.Test interface, meaning it can be run as a JUnit test. Your Android test cases should always extend TestCase or one of its descendants. The default constructor All test cases require a default constructor because, sometimes, depending on the test runner used, this is the only constructor that is invoked, and is also used for serialization. According to the documentation, this method is not intended to be used by "mere mortals" without calling setName(String name). Therefore, to appease the Gods, a common pattern is to use a default test case name in this constructor and invoke the given name constructor afterwards: public class MyTestCase extends TestCase {    public MyTestCase() {      this("MyTestCase Default Name");    }      public MyTestCase(String name) {      super(name);    } } The given name constructor This constructor takes a name as an argument to label the test case. It will appear in test reports and would be of much help when you try to identify where failed tests have come from. The setName() method There are some classes that extend TestCase that don't provide a given name constructor. In such cases, the only alternative is to call setName(String name). The AndroidTestCase base class This class can be used as a base class for general-purpose Android test cases. Use it when you need access to Android resources, databases, or files in the filesystem. Context is stored as a field in this class, which is conveniently named mContext and can be used inside the tests if needed, or the getContext() method can be used too. Tests based on this class can start more than one Activity using Context.startActivity(). There are various test cases in Android SDK that extend this base class: ApplicationTestCase<T extends Application> ProviderTestCase2<T extends ContentProvider> ServiceTestCase<T extends Service> When using the AndroidTestCase Java class, you inherit some base assertion methods that can be used; let's look at these in more detail. The assertActivityRequiresPermission() method The signature for this method is as follows: public void assertActivityRequiresPermission (String packageName, String className, String permission) Description This assertion method checks whether the launching of a particular Activity is protected by a specific permission. It takes the following three parameters: packageName: This is a string that indicates the package name of the activity to launch className: This is a string that indicates the class of the activity to launch permission: This is a string with the permission to check The Activity is launched and then SecurityException is expected, which mentions that the required permission is missing in the error message. The actual instantiation of an activity is not handled by this assertion, and thus, an Instrumentation is not needed. Example This test checks the requirement of the android.Manifest.permission.WRITE_EXTERNAL_STORAGE permission, which is needed to write to external storage, in the MyContactsActivity Activity: public void testActivityPermission() { String pkg = "com.blundell.tut"; String activity = PKG + ".MyContactsActivity"; String permission = android.Manifest.permission.CALL_PHONE; assertActivityRequiresPermission(pkg, activity, permission); } Always use the constants that describe the permissions from android.Manifest.permission, not the strings, so if the implementation changes, your code will still be valid. The assertReadingContentUriRequiresPermission method The signature for this method is as follows: public void assertReadingContentUriRequiresPermission(Uri uri, String permission) Description This assertion method checks whether reading from a specific URI requires the permission provided as a parameter. It takes the following two parameters: uri: This is the Uri that requires a permission to query permission: This is a string that contains the permission to query If a SecurityException class is generated, which contains the specified permission, this assertion is validated. Example This test tries to read contacts and verifies that the correct SecurityException is generated: public void testReadingContacts() {    Uri URI = ContactsContract.AUTHORITY_URI;    String PERMISSION = android.Manifest.permission.READ_CONTACTS;    assertReadingContentUriRequiresPermission(URI, PERMISSION); } The assertWritingContentUriRequiresPermission() method The signature for this method is as follows: public void assertWritingContentUriRequiresPermission (Uri uri,   String permission) Description This assertion method checks whether inserting into a specific Uri requires the permission provided as a parameter. It takes the following two parameters: uri: This is the Uri that requires a permission to query permission: This is a string that contains the permission to query If a SecurityException class is generated, which contains the specified permission, this assertion is validated. Example This test tries to write to Contacts and verifies that the correct SecurityException is generated: public void testWritingContacts() { Uri uri = ContactsContract.AUTHORITY_URI;    String permission = android.Manifest.permission.WRITE_CONTACTS; assertWritingContentUriRequiresPermission(uri, permission); } Instrumentation Instrumentation is instantiated by the system before any of the application code is run, thereby allowing monitoring of all the interactions between the system and the application. As with many other Android application components, instrumentation implementations are described in the AndroidManifest.xml under the tag <instrumentation>. However, with the advent of Gradle, this has now been automated for us, and we can change the properties of the instrumentation in the app's build.gradle file. The AndroidManifest file for your tests will be automatically generated: defaultConfig { testApplicationId 'com.blundell.tut.tests' testInstrumentationRunner   "android.test.InstrumentationTestRunner" } The values mentioned in the preceding code are also the defaults if you do not declare them, meaning that you don't have to have any of these parameters to start writing tests. The testApplicationId attribute defines the name of the package for your tests. As a default, it is your application under the test package name + tests. You can declare a custom test runner using testInstrumentationRunner. This is handy if you want to have tests run in a custom way, for example, parallel test execution. There are also many other parameters in development, and I would advise you to keep your eyes upon the Google Gradle plugin website (http://tools.android.com/tech-docs/new-build-system/user-guide). The ActivityMonitor inner class As mentioned earlier, the Instrumentation class is used to monitor the interaction between the system and the application or the Activities under test. The inner class Instrumentation ActivityMonitor allows the monitoring of a single Activity within an application. Example Let's pretend that we have a TextView in our Activity that holds a URL and has its auto link property set: <TextView        android_id="@+id/link        android_layout_width="match_parent"    android_layout_height="wrap_content"        android_text="@string/home"    android_autoLink="web" " /> If we want to verify that, when clicked, the hyperlink is correctly followed and some browser is invoked, we can create a test like this: public void testFollowLink() {        IntentFilter intentFilter = new IntentFilter(Intent.ACTION_VIEW);        intentFilter.addDataScheme("http");        intentFilter.addCategory(Intent.CATEGORY_BROWSABLE);          Instrumentation inst = getInstrumentation();        ActivityMonitor monitor = inst.addMonitor(intentFilter, null, false);        TouchUtils.clickView(this, linkTextView);        monitor.waitForActivityWithTimeout(3000);        int monitorHits = monitor.getHits();        inst.removeMonitor(monitor);          assertEquals(1, monitorHits);    } Here, we will do the following: Create an IntentFilter for intents that would open a browser. Add a monitor to our Instrumentation based on the IntentFilter class. Click on the hyperlink. Wait for the activity (hopefully the browser). Verify that the monitor hits were incremented. Remove the monitor. Using monitors, we can test even the most complex interactions with the system and other Activities. This is a very powerful tool to create integration tests. The InstrumentationTestCase class The InstrumentationTestCase class is the direct or indirect base class for various test cases that have access to Instrumentation. This is the list of the most important direct and indirect subclasses: ActivityTestCase ProviderTestCase2<T extends ContentProvider> SingleLaunchActivityTestCase<T extends Activity> SyncBaseInstrumentation ActivityInstrumentationTestCase2<T extends Activity> ActivityUnitTestCase<T extends Activity> The InstrumentationTestCase class is in the android.test package, and extends junit.framework.TestCase, which extends junit.framework.Assert. The launchActivity and launchActivityWithIntent method These utility methods are used to launch Activities from a test. If the Intent is not specified using the second option, a default Intent is used: public final T launchActivity (String pkg, Class<T> activityCls,   Bundle extras) The template class parameter T is used in activityCls and as the return type, limiting its use to Activities of that type. If you need to specify a custom Intent, you can use the following code that also adds the intent parameter: public final T launchActivityWithIntent (String pkg, Class<T>   activityCls, Intent intent) The sendKeys and sendRepeatedKeys methods While testing Activities' UI, you will face the need to simulate interaction with qwerty-based keyboards or DPAD buttons to send keys to complete fields, select shortcuts, or navigate throughout the different components. This is what the different sendKeys and sendRepeatedKeys are used for. There is one version of sendKeys that accepts integer keys values. They can be obtained from constants defined in the KeyEvent class. For example, we can use the sendKeys method in this way:    public void testSendKeyInts() {        requestMessageInputFocus();        sendKeys(                KeyEvent.KEYCODE_H,                KeyEvent.KEYCODE_E,                KeyEvent.KEYCODE_E,                KeyEvent.KEYCODE_E,                KeyEvent.KEYCODE_Y,                KeyEvent.KEYCODE_DPAD_DOWN,                KeyEvent.KEYCODE_ENTER);        String actual = messageInput.getText().toString();          assertEquals("HEEEY", actual);    } Here, we are sending H, E, and Y letter keys and then the ENTER key using their integer representations to the Activity under test. Alternatively, we can create a string by concatenating the keys we desire to send, discarding the KEYCODE prefix, and separating them with spaces that are ultimately ignored:      public void testSendKeyString() {        requestMessageInputFocus();          sendKeys("H 3*E Y DPAD_DOWN ENTER");        String actual = messageInput.getText().toString();          assertEquals("HEEEY", actual);    } Here, we did exactly the same as in the previous test but we used a String "H 3* EY DPAD_DOWN ENTER". Note that every key in the String can be prefixed by a repeating factor followed by * and the key to be repeated. We used 3*E in our previous example, which is the same as E E E, that is, three times the letter E. If sending repeated keys is what we need in our tests, there is also another alternative that is precisely intended for these cases: public void testSendRepeatedKeys() {        requestMessageInputFocus();          sendRepeatedKeys(                1, KeyEvent.KEYCODE_H,                3, KeyEvent.KEYCODE_E,                1, KeyEvent.KEYCODE_Y,                1, KeyEvent.KEYCODE_DPAD_DOWN,                1, KeyEvent.KEYCODE_ENTER);        String actual = messageInput.getText().toString();          assertEquals("HEEEY", actual);    } This is the same test implemented in a different manner. The repetition number precedes each key. The runTestOnUiThread helper method The runTestOnUiThread method is a helper method used to run portions of a test on the UI thread. We used this inside the method requestMessageInputFocus(); so that we can set the focus on our EditText before waiting for the application to be idle, using Instrumentation.waitForIdleSync(). Also, the runTestOnUiThread method throws an exception, so we have to deal with this case: private void requestMessageInputFocus() {        try {            runTestOnUiThread(new Runnable() {                @Override                public void run() {                    messageInput.requestFocus();                }            });        } catch (Throwable throwable) {            fail("Could not request focus.");        }        instrumentation.waitForIdleSync();    } Alternatively, as we have discussed before, to run a test on the UI thread, we can annotate it with @UiThreadTest. However, sometimes, we need to run only parts of the test on the UI thread because other parts of it are not suitable to run on that thread, for example, database calls, or we are using other helper methods that provide the infrastructure themselves to use the UI thread, for example the TouchUtils methods. Summary We investigated the most relevant building blocks and reusable patterns to create our tests. Along this journey, we: Understood the common assertions found in JUnit tests Explained the specialized assertions found in the Android SDK Explored Android mock objects and their use in Android tests Now that we have all the building blocks, it is time to start creating more and more tests to acquire the experience needed to master the technique. Resources for Article: Further resources on this subject: Android Virtual Device Manager [article] Signing an application in Android using Maven [article] The AsyncTask and HardwareTask Classes [article]
Read more
  • 0
  • 0
  • 7695
Modal Close icon
Modal Close icon