1 /* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * xscreensaver, Copyright (c) 2016-2017 Jamie Zawinski <jwz@jwz.org>
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
12 * The superclass of every saver's Daydream.
14 * Each Daydream needs a distinct subclass in order to show up in the list.
15 * We know which saver we are running by the subclass name; we know which
16 * API to use by how the subclass calls super().
19 package org.jwz.xscreensaver;
21 import android.view.Display;
22 import android.view.Surface;
23 import android.view.SurfaceHolder;
24 import android.view.SurfaceView;
25 import android.view.View;
26 import android.view.Window;
27 import android.view.WindowManager;
28 import android.view.KeyEvent;
29 import android.service.dreams.DreamService;
30 import android.view.GestureDetector;
31 import android.view.KeyEvent;
32 import android.view.MotionEvent;
33 import android.graphics.Bitmap;
34 import android.graphics.Canvas;
35 import android.os.Message;
36 import android.os.Handler;
37 import android.os.Looper;
38 import android.util.Log;
40 public class Daydream extends DreamService {
42 private class SaverView extends SurfaceView
43 implements SurfaceHolder.Callback {
45 private boolean initTried = false;
46 private jwxyz jwxyz_obj;
48 private GestureDetector detector;
50 private Runnable on_quit = new Runnable() {
53 finish(); // Exit the Daydream
58 super (Daydream.this);
59 getHolder().addCallback(this);
63 public void surfaceChanged (SurfaceHolder holder, int format,
64 int width, int height) {
66 if (width == 0 || height == 0) {
72 Log.d ("xscreensaver",
73 String.format("surfaceChanged: %dx%d", width, height));
78 Display d = view.getDisplay();
81 switch (d.getRotation()) {
82 case Surface.ROTATION_90: r = 90; break;
83 case Surface.ROTATION_180: r = 180; break;
84 case Surface.ROTATION_270: r = 270; break;
89 if (jwxyz_obj == null) {
90 jwxyz_obj = new jwxyz (jwxyz.saverNameOf (Daydream.this),
91 Daydream.this, screenshot, width, height,
92 holder.getSurface(), on_quit);
93 detector = new GestureDetector (Daydream.this, jwxyz_obj);
95 jwxyz_obj.resize (width, height);
102 public void surfaceCreated (SurfaceHolder holder) {
106 if (jwxyz_obj != null) {
114 public void surfaceDestroyed (SurfaceHolder holder) {
115 if (jwxyz_obj != null) {
122 public boolean onTouchEvent (MotionEvent event) {
123 detector.onTouchEvent (event);
124 if (event.getAction() == MotionEvent.ACTION_UP)
125 jwxyz_obj.dragEnded (event);
130 public boolean onKeyDown (int keyCode, KeyEvent event) {
131 // In the emulator, this doesn't receive keyboard arrow keys, PgUp, etc.
132 // Some other keys like "Home" are interpreted before we get here, and
133 // function keys do weird shit.
135 // TODO: Does this still work? And is the above still true?
137 if (view.jwxyz_obj != null)
138 view.jwxyz_obj.sendKeyEvent (event);
143 private SaverView view;
146 private void LOG (String fmt, Object... args) {
147 Log.d ("xscreensaver",
148 this.getClass().getSimpleName() + ": " +
149 String.format (fmt, args));
152 protected Daydream () {
156 // Called when jwxyz_abort() is called, or other exceptions are thrown.
160 public void uncaughtException (Thread thread, Throwable ex) {
163 String err = ex.toString();
164 LOG ("Caught exception: %s", err);
166 this.finish(); // Exit the Daydream
168 final AlertDialog.Builder b = new AlertDialog.Builder(this);
170 b.setCancelable (false);
171 b.setPositiveButton ("Bummer",
172 new DialogInterface.OnClickListener() {
173 public void onClick(DialogInterface d, int id) {
177 // #### This isn't working:
178 // "Attempted to add window with non-application token"
179 // "Unable to add window -- token null is not for an application"
180 // I think I need to get an "Activity" to run it on somehow?
182 new Handler (Looper.getMainLooper()).post (new Runnable() {
184 AlertDialog alert = b.create();
185 alert.setTitle (this.getClass().getSimpleName() + " crashed");
186 alert.setIcon(android.R.drawable.ic_dialog_alert);
191 old_handler.uncaughtException (thread, ex);
197 public void onAttachedToWindow() {
198 super.onAttachedToWindow();
200 setInteractive (true);
201 setFullscreen (true);
204 view = new SaverView ();
205 setContentView (view);
208 public void onDreamingStarted() {
209 super.onDreamingStarted();
210 // view.jwxyz_obj.start();
213 public void onDreamingStopped() {
214 super.onDreamingStopped();
215 view.jwxyz_obj.pause();
218 public void onDetachedFromWindow() {
219 super.onDetachedFromWindow();
221 if (view.jwxyz_obj != null)
222 view.jwxyz_obj.pause();
223 } catch (Exception exc) {
224 // Fun fact: Android swallows exceptions coming from here, then crashes
226 LOG ("onDetachedFromWindow: %s", exc.toString());
232 // At startup, before we have blanked the screen, save a screenshot
233 // for later use by the hacks.
235 private void saveScreenshot() {
236 View view = getWindow().getDecorView().getRootView();
238 LOG ("unable to get root view for screenshot");
241 // This doesn't work:
243 boolean was = view.isDrawingCacheEnabled();
244 if (!was) view.setDrawingCacheEnabled (true);
245 view.buildDrawingCache();
246 screenshot = view.getDrawingCache();
247 if (!was) view.setDrawingCacheEnabled (false);
248 if (screenshot == null) {
249 LOG ("unable to get screenshot bitmap from %s", view.toString());
251 screenshot = Bitmap.createBitmap (screenshot);
255 // This doesn't work either: width and height are both -1...
257 int w = view.getLayoutParams().width;
258 int h = view.getLayoutParams().height;
259 if (w <= 0 || h <= 0) {
260 LOG ("unable to get root view for screenshot");
262 screenshot = Bitmap.createBitmap (w, h, Bitmap.Config.ARGB_8888);
263 Canvas c = new Canvas (screenshot);
264 view.layout (0, 0, w, h);