Daydream interactive screen savers are a new feature in Android 4.2 (API Level 17). With Daydream, you can create a screen saver with animation, interaction, and just about anything else you would include in an Android Activity. Daydream screen savers are displayed while the user device is charging. Users with devices running Jelly Bean 4.2 can select and configure a Daydream screen saver in their display settings. In this tutorial we'll go through the required steps to create a Daydream screen saver for Android.
The sample Daydream we'll create in this tutorial will display a simple animation featuring the Android robot image used as default launcher icon. The user will be able to stop and start the animation by tapping the robots. The Daydream will display a grid with multiple instances of the rotating robot and a button the user can use to dismiss the Daydream, which will be placed randomly within the grid.
In your own projects, you can choose interactive screen saver elements that will reuse the views you have in existing apps, or web views that provide links to your projects. The code in this tutorial is simply intended to familiarize you with the process of creating a functioning interactive Daydream, but these potential applications can enhance user engagement with any existing projects you may have.
Tip: Daydream is only available on devices running version 4.2 of Android, which is API Level 17. If you don't have a device running API 17, you'll only be able to test your Daydream apps on the emulator. As long as your Android development environment has version 17 installed, you should be able to create an AVD (Android Virtual Device) on which the Daydream will run. During development, you can create a test Activity in which you place the same content as your Daydream apps. The Eclipse and Android development resources are particularly useful for Activities.
1. Create a Project
Step 1
Create a new Android Project in Eclipse. The app will have one class in it, which will be a Service. When you go through the process of creating your new Android project in Eclipse, select API Level 17 as both target and minimum SDK for your project. There's no need to let Eclipse create an Activity or layout file. You won't need one. You can, however, let it create a launcher icon. In the New Android Application "Configure Project" screen, uncheck "Create Activity" but leave "Create Custom Launcher Icon" checked. Choose the default Android robot icon; we are going to use it within the Daydream.
Step 2
Open your project Manifest file to configure the app as a Daydream. Include the following code within the Manifest application element.
<service android:name=".RobotDaydream" android:exported="true" android:label="@string/daydream_name"> <intent-filter> <action android:name="android.service.dreams.DreamService" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </service>
This allows your app to be listed in the Daydream options within the user's display settings. You can change the name of the service class "RobotDaydream" if you like, as long as you give your service class the same name when we create it. Add the specified label string to your application's "res/values/strings" file(s).
<string name="daydream_name">Spinning Androids</string>
This name will appear in the device display settings when selecting a Daydream.
Tip: The Manifest code above is complete for a functioning Daydream. However, you can opt to add a metadata element, linking to a resource where you can specify a settings Activity class for your app.
2. Define an Animation
Step 1
Before we get started on the Daydream Service class, we'll define an animation set resource. The little robot icons we display will rotate back and forth when the Daydream runs, so let's define this animation first. In your project "res" folder, create a new folder named "animator" and create a new file in it named "android_spin.xml". Inside the new XML file, define the animation.
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/linear_interpolator" android:ordering="together" > <objectAnimator android:duration="5000" android:propertyName="rotation" android:repeatCount="infinite" android:repeatMode="reverse" android:valueTo="360" android:valueType="floatType" /> </set>
You can alter the animation properties if you wish. This simply defines an animation that will rotate the target image 360 degrees in one direction over five seconds and back in the opposite direction. It will repeat continuously.
3. Create a Daydream Service
Step 1
In your project, create a new class in the main package. If Eclipse did not create a default package when you created the project, add one now by selecting the "src" folder and choosing File > New > Package and entering your package name. Add your new class to the package, naming it "RobotDaydream" or whatever you included in the Manifest service name attribute. Extend the opening line of the class declaration.
public class RobotDaydream extends DreamService implements OnClickListener
You will need the following imports in the class for the remainder of the code in this tutorial.
import java.util.Random; import android.animation.AnimatorInflater; import android.animation.AnimatorSet; import android.graphics.Color; import android.graphics.Point; import android.service.dreams.DreamService; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.GridLayout; import android.widget.ImageView;
Step 2
When you extend the Daydream class, there are a number of methods you can override to control the appearance and behavior of your screen saver. Inside your Service class, add the method outline for when the Daydream starts.
@Override public void onDreamingStarted() { //daydream started }
Now add the method outline for when Daydreaming stops.
@Override public void onDreamingStopped(){ //daydream stopped }
Add the method outline for when your Daydream is initially attached. You'll include setup tasks for the screen saver.
@Override public void onAttachedToWindow() { //setup daydream }
Any tidying up from setup will be placed inside the method for when the Daydream is detached, so add that next.
@Override public void onDetachedFromWindow() { //tidy up }
Lastly, add the method outline for handling clicks. Depending on their functionality, your Daydream apps may not always require all of these methods.
public void onClick(View v){ //handle clicks }
We will be working with each of these methods.
4. Prepare for Daydreaming
Step 1
At the top of your Daydream Service class, add some instance variables that we'll use to implement the animation and interaction. First you'll add a button so that the user can stop the Daydream.
private Button dismissBtn;
If you set your Daydream up to be interactive, which we'll do here, you'll need to manually implement a way to stop the Daydream. Otherwise, the default behavior for a Daydream is to stop when the user touches the screen. We won't be using the default behavior because we want to allow the user to interact with the views in our Daydream. We'll provide a button that allows the user to dismiss the Daydream instead.
Next, add two arrays.
private ImageView[] robotImgs; private AnimatorSet[] robotSets;
These will store the robot image views and animator sets for them. We'll use a constant to set the number of robots to display, using the number of rows and columns we want in the grid.
private final int ROWS_COLS=5; private final int NUM_ROBOTS=ROWS_COLS*ROWS_COLS;
Finally, we'll use a random number to determine where the stop button will be placed in the grid.
private int randPosn;
Step 2
The onAttachedToWindow method gives us the opportunity to carry out setup tasks for the Daydream. Call the superclass method inside the method.
super.onAttachedToWindow();
Set the Daydream to be interactive and occupy the full screen, hiding the status bar.
setInteractive(true); setFullscreen(true);
Step 3
Get a random number to determine where the stop button will be.
Random rand = new Random(); randPosn = rand.nextInt(NUM_ROBOTS);
Create a grid layout for the Daydream, setting the number of rows and columns using the constant.
GridLayout ddLayout = new GridLayout(this); ddLayout.setColumnCount(ROWS_COLS); ddLayout.setRowCount(ROWS_COLS);
Initialize the arrays.
robotSets = new AnimatorSet[NUM_ROBOTS]; robotImgs = new ImageView[NUM_ROBOTS];
Determine the width and height for each robot image in the grid.
Point screenSize = new Point(); getWindowManager().getDefaultDisplay().getSize(screenSize); int robotWidth = screenSize.x/ROWS_COLS; int robotHeight = screenSize.y/ROWS_COLS;
Step 4
Now we can loop through the arrays, adding the stop button and robots to the grid.
for(int r=0; r<NUM_ROBOTS; r++){ //add to grid }
Inside the loop, create some layout parameters using the width and height we calculated.
GridLayout.LayoutParams ddP = new GridLayout.LayoutParams(); ddP.width=robotWidth; ddP.height=robotHeight;
Check to make sure we are at the index allocated for the stop button.
if(r==randPosn){ //stop button } else{ //robot image view }
Inside the if block, create and add the stop button to the layout, setting display properties and listening for clicks.
dismissBtn = new Button(this); dismissBtn.setText("stop"); dismissBtn.setBackgroundColor(Color.WHITE); dismissBtn.setTextColor(Color.RED); dismissBtn.setOnClickListener(this); dismissBtn.setLayoutParams(ddP); ddLayout.addView(dismissBtn);
Inside the else block, create an Image View and set the launcher icon as its drawable, adding it to the layout.
robotImgs[r] = new ImageView(this); robotImgs[r].setImageResource(R.drawable.ic_launcher); ddLayout.addView(robotImgs[r], ddP);
Inside the else, create and add an animator set to the array, referencing the animation resource we created. You can alter the drawable image to suit one of your own.
robotSets[r] = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.android_spin);
Set the current robot image as target for the animation and listen for clicks on it.
robotSets[r].setTarget(robotImgs[r]); robotImgs[r].setOnClickListener(this);
After the for loop (but still inside the onAttachedToWindow method), set the content view to the layout we created and populated.
setContentView(ddLayout);
5. Handle Clicks
Step 1
Inside your onClick method, find out whether a robot image view or the stop button was clicked.
if(v instanceof Button && (Button)v==dismissBtn){ //stop button } else { //robot image }
Step 2
In the if block, finish the Daydream.
this.finish();
You must implement this for any interactive Daydreams you create (in which you call setInteractive(true)). The user will not be able to dismiss the screen saver the default way.
Step 3
Inside the else block, add a loop to iterate through the robot image views.
for(int r=0; r<NUM_ROBOTS; r++){ //check array }
Inside the loop, make sure that the index is not in the position designated for the stop button. If this is the case, the image view array entry will be empty.
if(r!=randPosn){ //check image view }
Inside the if block, find out if the current view is the one just clicked.
if((ImageView)v==robotImgs[r]){ //is the current view }
Inside this if, stop or start the animation depending on whether it's currently running.
if(robotSets[r].isStarted()) robotSets[r].cancel(); else robotSets[r].start();
This lets the user turn the animations on and off for each robot image view. Now that we've responded to the click, break out of the loop.
break;
6. Starting and Stopping Daydreaming
Step 1
In your onDreamingStarted method, call the superclass method.
super.onDreamingStarted();
Next, loop through the animations and start them.
for(int r=0; r<NUM_ROBOTS; r++){ if(r!=randPosn) robotSets[r].start(); }
Step 2
In your onDreamingStopped method, stop the animations.
for(int r=0; r<NUM_ROBOTS; r++){ if(r!=randPosn) robotSets[r].cancel(); }
Now call the superclass method.
super.onDreamingStopped();
Step 3
In the onDetachedFromWindow method, we can get rid of anything we set up in onAttachedToWindow. In this case we'll just stop listening for clicks.
for(int r=0; r<NUM_ROBOTS; r++){ if(r!=randPosn) robotImgs[r].setOnClickListener(null); }
Finally, call the superclass method.
super.onDetachedFromWindow();
Conclusion
This completes the basic Daydream app! You can test yours on the emulator or on a real device running Jelly Bean 4.2. Browsing to the Settings > Display section of the device menu will let you select the Daydream from the available list. Once it's selected, you can choose "Start Now" to see it in action. In your own projects, you can implement pretty much the same interactive and informational functions you would in an Activity, so you can use Daydreams to provide engaging access points for your existing apps. However, be aware that if your screen saver is using too much of the available processing resources, the Android system will stop it from running to allow the device to charge properly. Other options to explore in your Daydream apps include setting the screen brightness and providing a settings activity for user configuration.
Comments