Android Tutorial Android Daydream / DreamService tutorial

Android 4.2 includes a new powerful screen saver feature named Daydream.

A "dream" starts when the device is docked or charged and the screen timeouts. By default dreams are non-interactive, which means that once the user touches the screen the dream is dismissed. However dreams can also be interactive and include standard views (controls).

It is worth reading Google's blog about this feature: Android Developers Blog: Daydream: Interactive Screen Savers

The Daydream library allows you to create your own dreams.
The dream is handled by a service. The service name must be DreamService.

The dreams are set under Settings - Display - Daydreams.

Steps required to create a dream
- Add a service named DreamService.
- Add the following code to the manifest editor:
B4X:
AddApplicationText(<service
            android:name="anywheresoftware.b4a.objects.DreamServiceWrapper"
            android:exported="true"
            android:label="Dream Service Example">
            <intent-filter>
                <action android:name="android.service.dreams.DreamService" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
           </service>)
You can modify the label value. This value will appear in the dreams list (use this list during development to start the dream):

SS-2013-01-07_15.30.35.png


You can change the icon by changing the application icon.

- Set minSdkVersion and targetSdkVersion in the manifest editor to 17 (17 is Android 4.2).
- Reference android.jar from platform 17 or above (Tools - Configure Paths). You will probably need to first download it with Android SDK Manager.

Simple dream that draws random circles on the screen:
B4X:
Sub Process_Globals
   Private dd As Daydream
   Private timer1 As Timer
End Sub
Sub Service_Create
   
End Sub

Sub Service_Start (StartingIntent As Intent)
   dd.Initialize("dd")
   timer1.Initialize("timer1", 800)
End Sub

Sub dd_SizeChanged
   dd.Canvas.Initialize(dd.Panel)
End Sub

Sub dd_DreamStarted
   dd.Interactive = False
   timer1.Enabled = True
End Sub

Sub Timer1_Tick
   dd.Canvas.DrawCircle(Rnd(0, dd.Panel.Width), _
      Rnd(0, dd.Panel.Height), _
      Rnd(10dip, 100dip), _
      Rnd(0x80000001, 0), _
      True, 0)
   dd.Panel.Invalidate
End Sub
Sub dd_DreamStopped
   timer1.Enabled = False
End Sub

Sub Service_Destroy

End Sub

Important subs:
- Daydream should be initialized in Service_Start.
- SizeChanged event is raised when the main panel is first ready or after the user rotates the screen. In this sub you should build the layout (by adding views to the panel or by initializing the canvas and drawing on the panel).
- DreamStarted event is raised when the dream starts.
- DreamStopped event is raised when the dream stops.

Daydream.Canvas is a placeholder for a canvas. You should initialize it before using it (as done in the above example).

Dreams limitations
Services usually do not interact with UI elements. There are some limitations which you should be aware of:
- Views (and other activity objects) cannot be declared in Sub Process_Globals. You should instead fetch the views from the main panel as done in the WebView example.
- Layout files cannot be loaded.
- Percentage units cannot be used (100%x, 100%y).

Examples
Two examples are attached. The circles example is a dream that randomly draws circles on the screen. The webview example is an interactive dream that loads the URL that the user enters with WebView. The URL is saved in a file.

SS-2013-01-07_15.41.49.png
 

Attachments

  • Daydream_Circles.zip
    6.7 KB · Views: 961
  • Daydream_Webview.zip
    6.9 KB · Views: 937
  • Daydream_library1.0.zip
    4.8 KB · Views: 941

RiverRaid

Active Member
Licensed User
Longtime User
Hi Erel!

Is it possible to show Ads in the Daydream?

I tried following code:
B4X:
Sub dd_SizeChanged
  
        
        Dim AdView1 As AdView

        AdView1.Initialize("Ad", "xxxxxxxx")
           dd.Panel.AddView(AdView1, dd.Panel.Width / 2 - 160dip, dd.Panel.Height - 50dip, 320dip, 50dip) 
        AdView1.LoadAd

End Sub
But then the daydream crashes upon start :/

Thank you
 
Last edited:

RiverRaid

Active Member
Licensed User
Longtime User
Thanks for the answer..

This line causes the Error:
B4X:
AdView1.Initialize("Ad", "xxxxxxx")
The error message:
B4X:
LogCat connected to: B4A-Bridge: LGE Nexus 4-353918052980220
--------- beginning of /dev/log/main
Installing file.
GC_CONCURRENT freed 426K, 7% free 8961K/9564K, paused 2ms+1ms, total 28ms
Installing file.
GC_CONCURRENT freed 507K, 7% free 8962K/9564K, paused 34ms+1ms, total 54ms
WAIT_FOR_CONCURRENT_GC blocked 11ms
PackageAdded: package:com.ahadev.smokefree
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
** Service (playstore) Create **
** Service (playstore) Start **
GC_CONCURRENT freed 414K, 6% free 8945K/9500K, paused 1ms+2ms, total 15ms

** Activity (main) Pause, UserClosed = false **
** Service (dreamservice) Create **
** Service (dreamservice) Start **
dreamservice_dd_sizechanged (B4A line: 45)
AdView1.Initialize("Ad", "a14f3504d4aa2c9")
java.lang.NullPointerException
    at com.google.ads.AdView.<init>(SourceFile:87)
    at anywheresoftware.b4a.admobwrapper.AdViewWrapper.Initialize2(AdViewWrapper.java:79)
    at anywheresoftware.b4a.admobwrapper.AdViewWrapper.Initialize(AdViewWrapper.java:70)
    at com.ahadev.smokefree.dreamservice._dd_sizechanged(dreamservice.java:186)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:511)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:169)
    at anywheresoftware.b4a.BA$2.run(BA.java:272)
    at android.os.Handler.handleCallback(Handler.java:725)
    at android.os.Handler.dispatchMessage(Handler.java:92)
    at android.os.Looper.loop(Looper.java:137)
    at android.app.ActivityThread.main(ActivityThread.java:5041)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:511)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
    at dalvik.system.NativeStart.main(Native Method)
Installing file.
GC_CONCURRENT freed 436K, 6% free 8954K/9500K, paused 27ms+3ms, total 67ms
WAIT_FOR_CONCURRENT_GC blocked 45ms
PackageAdded: package:com.ahadev.smokefree
** Activity (main) Create, isFirst = true **
GC_CONCURRENT freed 401K, 6% free 8937K/9496K, paused 1ms+2ms, total 16ms
** Activity (main) Resume **
** Service (playstore) Create **
** Service (playstore) Start **
BillingSupported: true
received
** Activity (main) Pause, UserClosed = false **
** Service (dreamservice) Create **
** Service (dreamservice) Start **
dreamservice_dd_sizechanged (B4A line: 45)
AdView1.Initialize("Ad", "a14f3504d4aa2c9")
java.lang.NullPointerException
    at com.google.ads.AdView.<init>(SourceFile:87)
    at anywheresoftware.b4a.admobwrapper.AdViewWrapper.Initialize2(AdViewWrapper.java:79)
    at anywheresoftware.b4a.admobwrapper.AdViewWrapper.Initialize(AdViewWrapper.java:70)
    at com.ahadev.smokefree.dreamservice._dd_sizechanged(dreamservice.java:244)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:511)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:169)
    at anywheresoftware.b4a.BA$2.run(BA.java:272)
    at android.os.Handler.handleCallback(Handler.java:725)
    at android.os.Handler.dispatchMessage(Handler.java:92)
    at android.os.Looper.loop(Looper.java:137)
    at android.app.ActivityThread.main(ActivityThread.java:5041)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:511)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
    at dalvik.system.NativeStart.main(Native Method)
 

NeoTechni

Well-Known Member
Licensed User
Longtime User
I think one of the newer android versions must have messed with daydream because it's no longer working. I just get a blank screen, unless I touch it, then I get 1 frame drawn (then daydream closes as expected)

The timer is ticking fine, just nothing is drawing.
 

Cyan

Member
Licensed User
Longtime User
Sorry to necropost, but couldn't find this in the forums and it had me scratching my head why my Daydream didn't start, but quit immediately without warning.

If you're writing a daydream targeting API 21 or above, you will need to add the following line to the manifest:
B4X:
android:permission="android.permission.BIND_DREAM_SERVICE"

so that the manifest entry becomes:
B4X:
AddApplicationText(<service
            android:name="anywheresoftware.b4a.objects.DreamServiceWrapper"
            android:exported="true"
            android:label="Dream Service Example"
            android:permission="android.permission.BIND_DREAM_SERVICE">
            <intent-filter>
                <action android:name="android.service.dreams.DreamService" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
           </service>)

Reference: https://developer.android.com/reference/android/service/dreams/DreamService
 
Top