[TUT] DayDreams are as easy as counting sheep

DayDreaming is simple, if you have written an application with an Activity i.e everybody! You should be able to implement a simple daydream with little extra effort.

We are going to run through creating one and it will look something like this at the end:

DayDream(much smoother on a device, this is a GIF representation)

To create a DayDream we need to:

  • Create a DayDream *activity* to display our daydream
  • Update our Manifest to inform the system we can dream
  • Create a custom view that will perform something cool in our daydream

Ok here we go..

First we’ll create the DayDreamActivity, now technically it is not an Activity but a Service and in that idea we have to extend Service, but if you think of it as an Activity to display content with a lifecycle, I think it is a better concept.

In the DayDreamActivity we set a content view, this is the layout that will be shown if your day dream is being used. We also declare that we can handle user touch events, we don’t want the status bar shown when our day dream is shown and they can dim the screen.

DayDreamActivity.java:

package com.blundell.tutorial;

import android.service.dreams.DreamService;
import android.view.View;
import android.widget.Toast;

/**
 * Not really an Activity but just pretend it is one
 * <p/>
 * Where onCreate is onDreamingStarted
 * Where onPause is onDreamingStopped
 */
public class DayDreamActivity extends DreamService implements View.OnClickListener {

    @Override
    public void onDreamingStarted() {
        super.onDreamingStarted();
        // Removed the status bar
        setFullscreen(true);
        // We want to know about clicks
        setInteractive(true);
        // Dull the screen
        setScreenBright(false);

        // Acts just like an Activity
        setContentView(R.layout.dream_main);
        findViewById(R.id.dream_main_image).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        startApp();
    }

    private void startApp() {
        Toast.makeText(this, "Start your activity or another app on click", Toast.LENGTH_SHORT).show();
        // This is where you would normally start an Intent
        // don't forget to add the new activity flag
//        Intent intent = new Intent(this, null);
//        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//        startActivity(intent);
    }
}

After your create your DayDream, you need to declare it in your AndroidManifest like any other service:

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
  package="com.blundell.tutorial"
  android:versionCode="1"
  android:versionName="1.0">

  <uses-sdk
    android:minSdkVersion="14"
    android:targetSdkVersion="17" />
  <application
    android:label="@string/app_name"
    android:icon="@drawable/ic_launcher">
    <service
      android:name=".DayDreamActivity"
      android:label="@string/app_name"
      android:exported="true">
      <intent-filter>
        <action android:name="android.service.dreams.DreamService" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </service>
  </application>
</manifest>

That’s it, that would get you a basic daydream. However it doesn’t really do anything, so below I’m going to show you how to create a custom ImageView that will rotate any image you give it. For this example it is a spinning cloud daydream! We use a TimeAnimator to give us a callback on every frame for the system drawing. When we get this callback we change the Y rotation of the ImageView. You could do whatever you wanted for your daydream this is just one example.

SpinningImageView.java

package com.blundell.tutorial;

import android.animation.TimeAnimator;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ImageView;

/**
 * Simple CustomView that will rotate whatever image source you set
 */
public class SpinningImageView extends ImageView implements TimeAnimator.TimeListener {
    public static final int ROTATION_DELTA = 10;
    // This will tick every frame so you can update the view
    private TimeAnimator animatorTick;

    public SpinningImageView(Context context) {
        this(context, null);
    }

    public SpinningImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SpinningImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        animatorTick = new TimeAnimator();
        animatorTick.setTimeListener(this);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        animatorTick.start();
    }

    @Override
    public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) {
        setRotationY(getRotationY() + ROTATION_DELTA);
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        animatorTick.cancel();
    }
}

Then you use your custom view in the layout for the DayDreamActivity and you are done.

dream_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:gravity="center">

  <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/daydream_title" />

  <com.blundell.tutorial.SpinningImageView
    android:id="@+id/dream_main_image"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/dd_cloud"
    android:contentDescription="@null" />
</LinearLayout>

Take a look at the GitRepo for the source. DayDream Source Here

Inspired by the Google IO 2013 Talk Androids Do DayDream, I would highly recommend you watch it.

Enjoy! and ask any questions you like.