summaryrefslogtreecommitdiffstats
path: root/android/xscreensaver/src/org/jwz/xscreensaver
diff options
context:
space:
mode:
Diffstat (limited to 'android/xscreensaver/src/org/jwz/xscreensaver')
-rw-r--r--android/xscreensaver/src/org/jwz/xscreensaver/Activity.java169
-rw-r--r--android/xscreensaver/src/org/jwz/xscreensaver/App.java22
-rw-r--r--android/xscreensaver/src/org/jwz/xscreensaver/Daydream.java269
-rw-r--r--android/xscreensaver/src/org/jwz/xscreensaver/Settings.java179
-rw-r--r--android/xscreensaver/src/org/jwz/xscreensaver/SliderPreference.java160
-rw-r--r--android/xscreensaver/src/org/jwz/xscreensaver/TTFAnalyzer.java153
-rw-r--r--android/xscreensaver/src/org/jwz/xscreensaver/TVActivity.java50
-rw-r--r--android/xscreensaver/src/org/jwz/xscreensaver/Wallpaper.java128
-rw-r--r--android/xscreensaver/src/org/jwz/xscreensaver/jwxyz.java1115
9 files changed, 0 insertions, 2245 deletions
diff --git a/android/xscreensaver/src/org/jwz/xscreensaver/Activity.java b/android/xscreensaver/src/org/jwz/xscreensaver/Activity.java
deleted file mode 100644
index ac0ab4c..0000000
--- a/android/xscreensaver/src/org/jwz/xscreensaver/Activity.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * xscreensaver, Copyright (c) 2016 Jamie Zawinski <jwz@jwz.org>
- * and Dennis Sheil <dennis@panaceasupplies.com>
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation. No representations are made about the suitability of this
- * software for any purpose. It is provided "as is" without express or
- * implied warranty.
- *
- * This is the XScreenSaver "application" that just brings up the
- * Live Wallpaper preferences.
- */
-
-package org.jwz.xscreensaver;
-
-import android.app.WallpaperManager;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.os.Build;
-import android.os.Bundle;
-import android.view.View;
-import android.provider.Settings;
-import android.Manifest;
-import android.support.v4.app.ActivityCompat;
-import android.support.v4.content.ContextCompat;
-import android.os.Build;
-import android.content.pm.PackageManager;
-
-public class Activity extends android.app.Activity
- implements View.OnClickListener {
-
- private boolean wallpaperButtonClicked, daydreamButtonClicked;
- private final static int MY_REQ_READ_EXTERNAL_STORAGE = 271828;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- // openList();
- setContentView(R.layout.activity_xscreensaver);
- wallpaperButtonClicked = false;
- daydreamButtonClicked = false;
-
- findViewById(R.id.apply_wallpaper).setOnClickListener(this);
- findViewById(R.id.apply_daydream).setOnClickListener(this);
- }
-
- @Override
- public void onClick(View v) {
- switch (v.getId()) {
- case R.id.apply_wallpaper:
- wallpaperButtonClicked();
- break;
- case R.id.apply_daydream:
- daydreamButtonClicked();
- break;
- }
- }
-
- // synchronized when dealing with wallpaper state - perhaps can
- // narrow down more
- private synchronized void withProceed() {
- if (daydreamButtonClicked) {
- String action;
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
- action = Settings.ACTION_DREAM_SETTINGS;
- } else {
- action = Settings.ACTION_DISPLAY_SETTINGS;
- }
- startActivity(new Intent(action));
- } else if (wallpaperButtonClicked) {
- startActivity(new Intent(WallpaperManager.ACTION_LIVE_WALLPAPER_CHOOSER));
- }
- }
-
- private void wallpaperButtonClicked() {
- wallpaperButtonClicked = true;
- checkPermission();
- }
-
- private void daydreamButtonClicked() {
- daydreamButtonClicked = true;
- checkPermission();
- }
-
- void checkPermission() {
- // RES introduced in API 16
- String permission = Manifest.permission.READ_EXTERNAL_STORAGE;
- if (havePermission(permission)) {
- withProceed();
- } else {
- noPermission(permission);
- }
- }
-
- private void noPermission(String permission) {
- int myRequestCode;
- myRequestCode = MY_REQ_READ_EXTERNAL_STORAGE;
-
- if (permissionsDeniedRationale(permission)) {
- showDeniedRationale();
- } else {
- requestPermission(permission, myRequestCode);
- }
- }
-
- private boolean permissionsDeniedRationale(String permission) {
- boolean rationale = ActivityCompat.shouldShowRequestPermissionRationale(this,
- permission);
- return rationale;
- }
-
- private void requestPermission(String permission, int myRequestCode) {
- ActivityCompat.requestPermissions(this,
- new String[]{permission},
- myRequestCode);
-
- // myRequestCode is an app-defined int constant.
- // The callback method gets the result of the request.
- }
-
- // TODO: This method should be asynchronous, and not block the thread
- private void showDeniedRationale() {
- withProceed();
- }
-
- boolean havePermission(String permission) {
-
- if (Build.VERSION.SDK_INT < 16) {
- return true;
- }
-
- if (permissionGranted(permission)) {
- return true;
- }
-
- return false;
- }
-
- private boolean permissionGranted(String permission) {
- boolean check = ContextCompat.checkSelfPermission(this, permission) ==
- PackageManager.PERMISSION_GRANTED;
- return check;
- }
-
- public void proceedIfPermissionGranted(int[] grantResults) {
-
- // If request is cancelled, the result arrays are empty.
- if (grantResults.length > 0
- && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
- withProceed();
- } else if (grantResults.length > 0) {
- withProceed();
- }
- }
-
- @Override
- public void onRequestPermissionsResult(int requestCode,
- String permissions[], int[] grantResults) {
- switch (requestCode) {
- case MY_REQ_READ_EXTERNAL_STORAGE:
- proceedIfPermissionGranted(grantResults);
- }
- }
-
-}
diff --git a/android/xscreensaver/src/org/jwz/xscreensaver/App.java b/android/xscreensaver/src/org/jwz/xscreensaver/App.java
deleted file mode 100644
index 3d39788..0000000
--- a/android/xscreensaver/src/org/jwz/xscreensaver/App.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * xscreensaver, Copyright (c) 2016 Jamie Zawinski <jwz@jwz.org>
- * and Dennis Sheil <dennis@panaceasupplies.com>
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation. No representations are made about the suitability of this
- * software for any purpose. It is provided "as is" without express or
- * implied warranty.
- */
-
-package org.jwz.xscreensaver;
-
-import android.app.Application;
-
-public class App extends Application {
- public App() {
- super();
- }
-}
diff --git a/android/xscreensaver/src/org/jwz/xscreensaver/Daydream.java b/android/xscreensaver/src/org/jwz/xscreensaver/Daydream.java
deleted file mode 100644
index 372af95..0000000
--- a/android/xscreensaver/src/org/jwz/xscreensaver/Daydream.java
+++ /dev/null
@@ -1,269 +0,0 @@
-/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * xscreensaver, Copyright (c) 2016-2017 Jamie Zawinski <jwz@jwz.org>
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation. No representations are made about the suitability of this
- * software for any purpose. It is provided "as is" without express or
- * implied warranty.
- *
- * The superclass of every saver's Daydream.
- *
- * Each Daydream needs a distinct subclass in order to show up in the list.
- * We know which saver we are running by the subclass name; we know which
- * API to use by how the subclass calls super().
- */
-
-package org.jwz.xscreensaver;
-
-import android.view.Display;
-import android.view.Surface;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-import android.view.View;
-import android.view.Window;
-import android.view.WindowManager;
-import android.view.KeyEvent;
-import android.service.dreams.DreamService;
-import android.view.GestureDetector;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.os.Message;
-import android.os.Handler;
-import android.os.Looper;
-import android.util.Log;
-
-public class Daydream extends DreamService {
-
- private class SaverView extends SurfaceView
- implements SurfaceHolder.Callback {
-
- private boolean initTried = false;
- private jwxyz jwxyz_obj;
-
- private GestureDetector detector;
-
- private Runnable on_quit = new Runnable() {
- @Override
- public void run() {
- finish(); // Exit the Daydream
- }
- };
-
- SaverView () {
- super (Daydream.this);
- getHolder().addCallback(this);
- }
-
- @Override
- public void surfaceChanged (SurfaceHolder holder, int format,
- int width, int height) {
-
- if (width == 0 || height == 0) {
- detector = null;
- jwxyz_obj.close();
- jwxyz_obj = null;
- }
-
- Log.d ("xscreensaver",
- String.format("surfaceChanged: %dx%d", width, height));
-
- /*
- double r = 0;
-
- Display d = view.getDisplay();
-
- if (d != null) {
- switch (d.getRotation()) {
- case Surface.ROTATION_90: r = 90; break;
- case Surface.ROTATION_180: r = 180; break;
- case Surface.ROTATION_270: r = 270; break;
- }
- }
- */
-
- if (jwxyz_obj == null) {
- jwxyz_obj = new jwxyz (jwxyz.saverNameOf (Daydream.this),
- Daydream.this, screenshot, width, height,
- holder.getSurface(), on_quit);
- detector = new GestureDetector (Daydream.this, jwxyz_obj);
- } else {
- jwxyz_obj.resize (width, height);
- }
-
- jwxyz_obj.start();
- }
-
- @Override
- public void surfaceCreated (SurfaceHolder holder) {
- if (!initTried) {
- initTried = true;
- } else {
- if (jwxyz_obj != null) {
- jwxyz_obj.close();
- jwxyz_obj = null;
- }
- }
- }
-
- @Override
- public void surfaceDestroyed (SurfaceHolder holder) {
- if (jwxyz_obj != null) {
- jwxyz_obj.close();
- jwxyz_obj = null;
- }
- }
-
- @Override
- public boolean onTouchEvent (MotionEvent event) {
- detector.onTouchEvent (event);
- if (event.getAction() == MotionEvent.ACTION_UP)
- jwxyz_obj.dragEnded (event);
- return true;
- }
-
- @Override
- public boolean onKeyDown (int keyCode, KeyEvent event) {
- // In the emulator, this doesn't receive keyboard arrow keys, PgUp, etc.
- // Some other keys like "Home" are interpreted before we get here, and
- // function keys do weird shit.
-
- // TODO: Does this still work? And is the above still true?
-
- if (view.jwxyz_obj != null)
- view.jwxyz_obj.sendKeyEvent (event);
- return true;
- }
- }
-
- private SaverView view;
- Bitmap screenshot;
-
- private void LOG (String fmt, Object... args) {
- Log.d ("xscreensaver",
- this.getClass().getSimpleName() + ": " +
- String.format (fmt, args));
- }
-
- protected Daydream () {
- super();
- }
-
- // Called when jwxyz_abort() is called, or other exceptions are thrown.
- //
-/*
- @Override
- public void uncaughtException (Thread thread, Throwable ex) {
-
- renderer = null;
- String err = ex.toString();
- LOG ("Caught exception: %s", err);
-
- this.finish(); // Exit the Daydream
-
- final AlertDialog.Builder b = new AlertDialog.Builder(this);
- b.setMessage (err);
- b.setCancelable (false);
- b.setPositiveButton ("Bummer",
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface d, int id) {
- }
- });
-
- // #### This isn't working:
- // "Attempted to add window with non-application token"
- // "Unable to add window -- token null is not for an application"
- // I think I need to get an "Activity" to run it on somehow?
-
- new Handler (Looper.getMainLooper()).post (new Runnable() {
- public void run() {
- AlertDialog alert = b.create();
- alert.setTitle (this.getClass().getSimpleName() + " crashed");
- alert.setIcon(android.R.drawable.ic_dialog_alert);
- alert.show();
- }
- });
-
- old_handler.uncaughtException (thread, ex);
- }
-*/
-
-
- @Override
- public void onAttachedToWindow() {
- super.onAttachedToWindow();
-
- setInteractive (true);
- setFullscreen (true);
- saveScreenshot();
-
- view = new SaverView ();
- setContentView (view);
- }
-
- public void onDreamingStarted() {
- super.onDreamingStarted();
- // view.jwxyz_obj.start();
- }
-
- public void onDreamingStopped() {
- super.onDreamingStopped();
- view.jwxyz_obj.pause();
- }
-
- public void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- try {
- if (view.jwxyz_obj != null)
- view.jwxyz_obj.pause();
- } catch (Exception exc) {
- // Fun fact: Android swallows exceptions coming from here, then crashes
- // elsewhere.
- LOG ("onDetachedFromWindow: %s", exc.toString());
- throw exc;
- }
- }
-
-
- // At startup, before we have blanked the screen, save a screenshot
- // for later use by the hacks.
- //
- private void saveScreenshot() {
- View view = getWindow().getDecorView().getRootView();
- if (view == null) {
- LOG ("unable to get root view for screenshot");
- } else {
-
- // This doesn't work:
- /*
- boolean was = view.isDrawingCacheEnabled();
- if (!was) view.setDrawingCacheEnabled (true);
- view.buildDrawingCache();
- screenshot = view.getDrawingCache();
- if (!was) view.setDrawingCacheEnabled (false);
- if (screenshot == null) {
- LOG ("unable to get screenshot bitmap from %s", view.toString());
- } else {
- screenshot = Bitmap.createBitmap (screenshot);
- }
- */
-
- // This doesn't work either: width and height are both -1...
-
- int w = view.getLayoutParams().width;
- int h = view.getLayoutParams().height;
- if (w <= 0 || h <= 0) {
- LOG ("unable to get root view for screenshot");
- } else {
- screenshot = Bitmap.createBitmap (w, h, Bitmap.Config.ARGB_8888);
- Canvas c = new Canvas (screenshot);
- view.layout (0, 0, w, h);
- view.draw (c);
- }
- }
- }
-}
diff --git a/android/xscreensaver/src/org/jwz/xscreensaver/Settings.java b/android/xscreensaver/src/org/jwz/xscreensaver/Settings.java
deleted file mode 100644
index 17bac0f..0000000
--- a/android/xscreensaver/src/org/jwz/xscreensaver/Settings.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * xscreensaver, Copyright (c) 2016 Jamie Zawinski <jwz@jwz.org>
- * and Dennis Sheil <dennis@panaceasupplies.com>
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation. No representations are made about the suitability of this
- * software for any purpose. It is provided "as is" without express or
- * implied warranty.
- *
- * The superclass of every saver's preferences panel.
- *
- * The only reason the subclasses of this class exist is so that we know
- * which "_settings.xml" to read -- we extract the base name from self's
- * class.
- *
- * project/xscreensaver/res/xml/SAVER_dream.xml refers to it as
- * android:settingsActivity="SAVER_Settings". If there was some way
- * to pass an argument from the XML into here, or to otherwise detect
- * which Dream was instantiating this Settings, we wouldn't need those
- * hundreds of Settings subclasses.
- */
-
-package org.jwz.xscreensaver;
-
-import android.content.SharedPreferences;
-import android.os.Bundle;
-
-import android.content.SharedPreferences;
-import android.preference.PreferenceActivity;
-import android.preference.Preference;
-import android.preference.ListPreference;
-import android.preference.EditTextPreference;
-import android.preference.CheckBoxPreference;
-import org.jwz.xscreensaver.SliderPreference;
-
-import org.jwz.xscreensaver.R;
-import java.util.Map;
-import java.lang.reflect.Field;
-
-public abstract class Settings extends PreferenceActivity
- implements SharedPreferences.OnSharedPreferenceChangeListener {
-
- @Override
- protected void onCreate (Bundle icicle) {
- super.onCreate (icicle);
-
- // Extract the saver name from e.g. "BouncingCowSettings"
- String name = this.getClass().getSimpleName();
- String tail = "Settings";
- if (name.endsWith(tail))
- name = name.substring (0, name.length() - tail.length());
- name = name.toLowerCase();
-
- // #### All of these have been deprecated:
- // getPreferenceManager()
- // addPreferencesFromResource(int)
- // findPreference(CharSequence)
-
- getPreferenceManager().setSharedPreferencesName (name);
-
- // read R.xml.SAVER_settings dynamically
- int res = -1;
- String pref_class = name + "_settings";
- try { res = R.xml.class.getDeclaredField(pref_class).getInt (null); }
- catch (Exception e) { }
- if (res != -1)
- addPreferencesFromResource (res);
-
- final int res_final = res;
-
- SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
- prefs.registerOnSharedPreferenceChangeListener (this);
- updateAllPrefsSummaries (prefs);
-
- // Find the "Reset to defaults" button and install a click handler on it.
- //
- Preference reset = findPreference (name + "_reset");
- reset.setOnPreferenceClickListener(
- new Preference.OnPreferenceClickListener() {
- @Override
- public boolean onPreferenceClick(Preference preference) {
-
- SharedPreferences prefs =
- getPreferenceManager().getSharedPreferences();
-
- // Wipe everything from the preferences hash, then reload defaults.
- prefs.edit().clear().commit();
- getPreferenceScreen().removeAll();
- addPreferencesFromResource (res_final);
-
- // I guess we need to re-get this after the removeAll?
- prefs = getPreferenceManager().getSharedPreferences();
-
- // But now we need to iterate over every Preference widget and
- // push the new value down into it. If you think this all looks
- // ridiculously non-object-oriented and completely insane, that's
- // because it is.
-
- Map <String, ?> keys = prefs.getAll();
- for (Map.Entry <String, ?> entry : keys.entrySet()) {
- String key = entry.getKey();
- String val = String.valueOf (entry.getValue());
-
- Preference pref = findPreference (key);
- if (pref instanceof ListPreference) {
- ((ListPreference) pref).setValue (prefs.getString (key, ""));
- } else if (pref instanceof SliderPreference) {
- ((SliderPreference) pref).setValue (prefs.getFloat (key, 0));
- } else if (pref instanceof EditTextPreference) {
- ((EditTextPreference) pref).setText (prefs.getString (key, ""));
- } else if (pref instanceof CheckBoxPreference) {
- ((CheckBoxPreference) pref).setChecked (
- prefs.getBoolean (key,false));
- }
-
- updatePrefsSummary (prefs, pref);
- }
- return true;
- }
- });
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
- prefs.registerOnSharedPreferenceChangeListener (this);
- updateAllPrefsSummaries(prefs);
- }
-
- @Override
- protected void onPause() {
- getPreferenceManager().getSharedPreferences().
- unregisterOnSharedPreferenceChangeListener(this);
- super.onPause();
- }
-
- @Override
- protected void onDestroy() {
- getPreferenceManager().getSharedPreferences().
- unregisterOnSharedPreferenceChangeListener(this);
- super.onDestroy();
- }
-
- public void onSharedPreferenceChanged (SharedPreferences sharedPreferences,
- String key) {
- updatePrefsSummary(sharedPreferences, findPreference(key));
- }
-
- protected void updatePrefsSummary(SharedPreferences sharedPreferences,
- Preference pref) {
- if (pref == null)
- return;
-
- if (pref instanceof ListPreference) {
- pref.setTitle (((ListPreference) pref).getEntry());
- } else if (pref instanceof SliderPreference) {
- float v = ((SliderPreference) pref).getValue();
- int i = (int) Math.floor (v);
- if (v == i)
- pref.setSummary (String.valueOf (i));
- else
- pref.setSummary (String.valueOf (v));
- } else if (pref instanceof EditTextPreference) {
- pref.setSummary (((EditTextPreference) pref).getText());
- }
- }
-
- protected void updateAllPrefsSummaries(SharedPreferences prefs) {
-
- Map <String, ?> keys = prefs.getAll();
- for (Map.Entry <String, ?> entry : keys.entrySet()) {
- updatePrefsSummary (prefs, findPreference (entry.getKey()));
- }
- }
-}
diff --git a/android/xscreensaver/src/org/jwz/xscreensaver/SliderPreference.java b/android/xscreensaver/src/org/jwz/xscreensaver/SliderPreference.java
deleted file mode 100644
index c1a1a1d..0000000
--- a/android/xscreensaver/src/org/jwz/xscreensaver/SliderPreference.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * xscreensaver, Copyright (c) 2016 Jamie Zawinski <jwz@jwz.org>
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation. No representations are made about the suitability of this
- * software for any purpose. It is provided "as is" without express or
- * implied warranty.
- *
- * A numeric preference as a slider, inline in the preferences list.
- * XML options include:
- *
- * low, high (floats) -- smallest and largest allowed values.
- * If low > high, the value increases as the slider's thumb moves left.
- *
- * lowLabel, highLabel (strings) -- labels shown at the left and right
- * ends of the slider.
- *
- * integral (boolean) -- whether to use whole numbers instead of floats;
- */
-
-package org.jwz.xscreensaver;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.content.res.Resources;
-import android.preference.Preference;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.SeekBar;
-import android.widget.TextView;
-import android.util.Log;
-
-public class SliderPreference extends Preference {
-
- protected float low, high;
- protected String low_label, high_label;
- protected boolean integral;
- protected float mValue;
- protected int seekbar_ticks;
-
- public SliderPreference(Context context, AttributeSet attrs) {
- this (context, attrs, 0);
- }
-
- public SliderPreference (Context context, AttributeSet attrs, int defStyle) {
- super (context, attrs, defStyle);
-
- Resources res = context.getResources();
-
- // Parse these from the "<SliderPreference>" tag
- low = Float.parseFloat (attrs.getAttributeValue (null, "low"));
- high = Float.parseFloat (attrs.getAttributeValue (null, "high"));
- integral = attrs.getAttributeBooleanValue (null, "integral", false);
- low_label = res.getString(
- attrs.getAttributeResourceValue (null, "lowLabel", 0));
- high_label = res.getString(
- attrs.getAttributeResourceValue (null, "highLabel", 0));
-
- seekbar_ticks = (integral
- ? (int) Math.floor (Math.abs (high - low))
- : 100000);
-
- setWidgetLayoutResource (R.layout.slider_preference);
- }
-
-
- @Override
- protected void onSetInitialValue (boolean restore, Object def) {
- if (restore) {
- mValue = getPersistedFloat (low);
- } else {
- mValue = (Float) def;
- persistFloat (mValue);
- }
- //Log.d("xscreensaver", String.format("SLIDER INIT %s: %f",
- // low_label, mValue));
- }
-
- @Override
- protected Object onGetDefaultValue(TypedArray a, int index) {
- return a.getFloat (index, low);
- }
-
-
- public float getValue() {
- return mValue;
- }
-
- public void setValue (float value) {
-
- if (low < high) {
- value = Math.max (low, Math.min (high, value));
- } else {
- value = Math.max (high, Math.min (low, value));
- }
-
- if (integral)
- value = Math.round (value);
-
- if (value != mValue) {
- //Log.d("xscreensaver", String.format("SLIDER %s: %f", low_label, value));
- persistFloat (value);
- mValue = value;
- notifyChanged();
- }
- }
-
-
- @Override
- protected View onCreateView (ViewGroup parent) {
- View view = super.onCreateView(parent);
-
- TextView low_view = (TextView)
- view.findViewById (R.id.slider_preference_low);
- low_view.setText (low_label);
-
- TextView high_view = (TextView)
- view.findViewById (R.id.slider_preference_high);
- high_view.setText (high_label);
-
- SeekBar seekbar = (SeekBar)
- view.findViewById (R.id.slider_preference_seekbar);
- seekbar.setMax (seekbar_ticks);
-
- float ratio = (mValue - low) / (high - low);
- int seek_value = (int) (ratio * (float) seekbar_ticks);
-
- seekbar.setProgress (seek_value);
-
- final SliderPreference slider = this;
-
- seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
- }
-
- @Override
- public void onProgressChanged (SeekBar seekBar, int progress,
- boolean fromUser) {
- if (fromUser) {
- float ratio = (float) progress / (float) seekbar_ticks;
- float value = low + (ratio * (high - low));
- slider.setValue (value);
- callChangeListener (progress);
- }
- }
- });
-
- return view;
- }
-}
diff --git a/android/xscreensaver/src/org/jwz/xscreensaver/TTFAnalyzer.java b/android/xscreensaver/src/org/jwz/xscreensaver/TTFAnalyzer.java
deleted file mode 100644
index 3d01345..0000000
--- a/android/xscreensaver/src/org/jwz/xscreensaver/TTFAnalyzer.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
-
- * Copyright (C) 2011 George Yunaev @ Ulduzsoft
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
-
- http://www.ulduzsoft.com/2012/01/enumerating-the-fonts-on-android-platform/
- */
-
-package org.jwz.xscreensaver;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.util.HashMap;
-
-// The class which loads the TTF file, parses it and returns the TTF font name
-class TTFAnalyzer
-{
- // This function parses the TTF file and returns the font name specified in the file
- public String getTtfFontName( String fontFilename )
- {
- try
- {
- // Parses the TTF file format.
- // See http://developer.apple.com/fonts/ttrefman/rm06/Chap6.html
- m_file = new RandomAccessFile( fontFilename, "r" );
-
- // Read the version first
- int version = readDword();
-
- // The version must be either 'true' (0x74727565) or 0x00010000 or 'OTTO' (0x4f54544f) for CFF style fonts.
- if ( version != 0x74727565 && version != 0x00010000 && version != 0x4f54544f)
- return null;
-
- // The TTF file consist of several sections called "tables", and we need to know how many of them are there.
- int numTables = readWord();
-
- // Skip the rest in the header
- readWord(); // skip searchRange
- readWord(); // skip entrySelector
- readWord(); // skip rangeShift
-
- // Now we can read the tables
- for ( int i = 0; i < numTables; i++ )
- {
- // Read the table entry
- int tag = readDword();
- readDword(); // skip checksum
- int offset = readDword();
- int length = readDword();
-
- // Now here' the trick. 'name' field actually contains the textual string name.
- // So the 'name' string in characters equals to 0x6E616D65
- if ( tag == 0x6E616D65 )
- {
- // Here's the name section. Read it completely into the allocated buffer
- byte[] table = new byte[ length ];
-
- m_file.seek( offset );
- read( table );
-
- // This is also a table. See http://developer.apple.com/fonts/ttrefman/rm06/Chap6name.html
- // According to Table 36, the total number of table records is stored in the second word, at the offset 2.
- // Getting the count and string offset - remembering it's big endian.
- int count = getWord( table, 2 );
- int string_offset = getWord( table, 4 );
-
- // Record starts from offset 6
- for ( int record = 0; record < count; record++ )
- {
- // Table 37 tells us that each record is 6 words -> 12 bytes, and that the nameID is 4th word so its offset is 6.
- // We also need to account for the first 6 bytes of the header above (Table 36), so...
- int nameid_offset = record * 12 + 6;
- int platformID = getWord( table, nameid_offset );
- int nameid_value = getWord( table, nameid_offset + 6 );
-
- // Table 42 lists the valid name Identifiers. We're interested in 4 but not in Unicode encoding (for simplicity).
- // The encoding is stored as PlatformID and we're interested in Mac encoding
- if ( nameid_value == 4 && platformID == 1 )
- {
- // We need the string offset and length, which are the word 6 and 5 respectively
- int name_length = getWord( table, nameid_offset + 8 );
- int name_offset = getWord( table, nameid_offset + 10 );
-
- // The real name string offset is calculated by adding the string_offset
- name_offset = name_offset + string_offset;
-
- // Make sure it is inside the array
- if ( name_offset >= 0 && name_offset + name_length < table.length )
- return new String( table, name_offset, name_length );
- }
- }
- }
- }
-
- return null;
- }
- catch (FileNotFoundException e)
- {
- // Permissions?
- return null;
- }
- catch (IOException e)
- {
- // Most likely a corrupted font file
- return null;
- }
- }
-
- // Font file; must be seekable
- private RandomAccessFile m_file = null;
-
- // Helper I/O functions
- private int readByte() throws IOException
- {
- return m_file.read() & 0xFF;
- }
-
- private int readWord() throws IOException
- {
- int b1 = readByte();
- int b2 = readByte();
-
- return b1 << 8 | b2;
- }
-
- private int readDword() throws IOException
- {
- int b1 = readByte();
- int b2 = readByte();
- int b3 = readByte();
- int b4 = readByte();
-
- return b1 << 24 | b2 << 16 | b3 << 8 | b4;
- }
-
- private void read( byte [] array ) throws IOException
- {
- if ( m_file.read( array ) != array.length )
- throw new IOException();
- }
-
- // Helper
- private int getWord( byte [] array, int offset )
- {
- int b1 = array[ offset ] & 0xFF;
- int b2 = array[ offset + 1 ] & 0xFF;
-
- return b1 << 8 | b2;
- }
-}
diff --git a/android/xscreensaver/src/org/jwz/xscreensaver/TVActivity.java b/android/xscreensaver/src/org/jwz/xscreensaver/TVActivity.java
deleted file mode 100644
index 0015c9d..0000000
--- a/android/xscreensaver/src/org/jwz/xscreensaver/TVActivity.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * xscreensaver, Copyright (c) 2017 Jamie Zawinski <jwz@jwz.org>
- * and Dennis Sheil <dennis@panaceasupplies.com>
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation. No representations are made about the suitability of this
- * software for any purpose. It is provided "as is" without express or
- * implied warranty.
- *
- * This is the XScreenSaver "application" that just brings up the
- * Daydream preferences for Android TV.
- */
-
-package org.jwz.xscreensaver;
-
-import android.app.Activity;
-import android.app.WallpaperManager;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.os.Build;
-import android.os.Bundle;
-import android.view.View;
-import android.provider.Settings;
-
-public class TVActivity extends Activity
- implements View.OnClickListener {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_tv_xscreensaver);
- findViewById(R.id.apply_daydream).setOnClickListener(this);
- }
-
- @Override
- public void onClick(View v) {
- switch (v.getId()) {
-
- case R.id.apply_daydream:
- String action;
- Intent intent = new Intent(android.provider.Settings.ACTION_SETTINGS);
- startActivityForResult(intent, 0);
- break;
- }
- }
-}
diff --git a/android/xscreensaver/src/org/jwz/xscreensaver/Wallpaper.java b/android/xscreensaver/src/org/jwz/xscreensaver/Wallpaper.java
deleted file mode 100644
index 93896f2..0000000
--- a/android/xscreensaver/src/org/jwz/xscreensaver/Wallpaper.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * xscreensaver, Copyright (c) 2016-2018 Jamie Zawinski <jwz@jwz.org>
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation. No representations are made about the suitability of this
- * software for any purpose. It is provided "as is" without express or
- * implied warranty.
- *
- * The superclass of every saver's Wallpaper.
- *
- * Each Wallpaper needs a distinct subclass in order to show up in the list.
- * We know which saver we are running by the subclass name; we know which
- * API to use by how the subclass calls super().
- */
-
-package org.jwz.xscreensaver;
-
-import android.content.res.Configuration;
-import android.service.wallpaper.WallpaperService;
-import android.view.GestureDetector;
-import android.view.SurfaceHolder;
-import android.util.Log;
-import java.lang.RuntimeException;
-import java.lang.Thread;
-import org.jwz.xscreensaver.jwxyz;
-import android.graphics.PixelFormat;
-import android.view.WindowManager;
-import android.view.Display;
-import android.graphics.Point;
-
-public class Wallpaper extends WallpaperService
-/*implements GestureDetector.OnGestureListener,
- GestureDetector.OnDoubleTapListener, */ {
-
- /* TODO: Input! */
- private Engine engine;
-
- @Override
- public Engine onCreateEngine() {
- // Log.d("xscreensaver", "tid = " + Thread.currentThread().getId());
- engine = new XScreenSaverGLEngine();
- return engine;
- }
-
- @Override
- public void onConfigurationChanged(Configuration config) {
- super.onConfigurationChanged(config);
- Log.d("xscreensaver", "wallpaper onConfigurationChanged");
- /*
- WindowManager wm = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
- Display display = wm.getDefaultDisplay();
- Point size = new Point();
- display.getSize(size);
- int width = size.x;
- int height = size.y;
- engine.onSurfaceChanged(engine.getSurfaceHolder(), PixelFormat.RGBA_8888, width, height);
- */
-
- }
-
- class XScreenSaverGLEngine extends Engine {
-
- private boolean initTried = false;
- private jwxyz jwxyz_obj;
-
- @Override
- public void onSurfaceCreated (SurfaceHolder holder) {
- super.onSurfaceCreated(holder);
-
- if (!initTried) {
- initTried = true;
- } else {
- if (jwxyz_obj != null) {
- jwxyz_obj.close();
- jwxyz_obj = null;
- }
- }
- }
-
- @Override
- public void onVisibilityChanged(final boolean visible) {
- if (jwxyz_obj != null) {
- if (visible)
- jwxyz_obj.start();
- else
- jwxyz_obj.pause();
- }
- }
-
- @Override
- public void onSurfaceChanged (SurfaceHolder holder, int format,
- int width, int height) {
-
- super.onSurfaceChanged(holder, format, width, height);
-
- if (width == 0 || height == 0) {
- jwxyz_obj.close();
- jwxyz_obj = null;
- }
-
- Log.d ("xscreensaver",
- String.format("surfaceChanged: %dx%d", width, height));
-
- if (jwxyz_obj == null) {
- jwxyz_obj = new jwxyz (jwxyz.saverNameOf(Wallpaper.this),
- Wallpaper.this, null, width, height,
- holder.getSurface(), null);
- } else {
- jwxyz_obj.resize (width, height);
- }
-
- jwxyz_obj.start();
- }
-
- @Override
- public void onSurfaceDestroyed (SurfaceHolder holder) {
- super.onSurfaceDestroyed (holder);
-
- if (jwxyz_obj != null) {
- jwxyz_obj.close();
- jwxyz_obj = null;
- }
- }
- }
-}
diff --git a/android/xscreensaver/src/org/jwz/xscreensaver/jwxyz.java b/android/xscreensaver/src/org/jwz/xscreensaver/jwxyz.java
deleted file mode 100644
index a22a26d..0000000
--- a/android/xscreensaver/src/org/jwz/xscreensaver/jwxyz.java
+++ /dev/null
@@ -1,1115 +0,0 @@
-/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * xscreensaver, Copyright (c) 2016-2018 Jamie Zawinski <jwz@jwz.org>
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation. No representations are made about the suitability of this
- * software for any purpose. It is provided "as is" without express or
- * implied warranty.
- *
- * This class is how the C implementation of jwxyz calls back into Java
- * to do things that OpenGL does not have access to without Java-based APIs.
- * It is the Java companion to jwxyz-android.c and screenhack-android.c.
- */
-
-package org.jwz.xscreensaver;
-
-import java.util.Map;
-import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.ArrayList;
-import java.util.Random;
-import android.app.AlertDialog;
-import android.view.KeyEvent;
-import android.content.SharedPreferences;
-import android.content.Context;
-import android.content.ContentResolver;
-import android.content.DialogInterface;
-import android.content.res.AssetManager;
-import android.graphics.Typeface;
-import android.graphics.Rect;
-import android.graphics.Paint;
-import android.graphics.Paint.FontMetrics;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Matrix;
-import android.net.Uri;
-import android.view.GestureDetector;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import java.net.URL;
-import java.nio.ByteBuffer;
-import java.io.File;
-import java.io.InputStream;
-import java.io.FileOutputStream;
-import java.lang.InterruptedException;
-import java.lang.Runnable;
-import java.lang.Thread;
-import java.util.TimerTask;
-import android.database.Cursor;
-import android.provider.MediaStore;
-import android.provider.MediaStore.MediaColumns;
-import android.media.ExifInterface;
-import org.jwz.xscreensaver.TTFAnalyzer;
-import android.util.Log;
-import android.view.Surface;
-import android.Manifest;
-import android.support.v4.app.ActivityCompat;
-import android.support.v4.content.ContextCompat;
-import android.os.Build;
-import android.content.pm.PackageManager;
-
-public class jwxyz
- implements GestureDetector.OnGestureListener,
- GestureDetector.OnDoubleTapListener {
-
- private class PrefListener
- implements SharedPreferences.OnSharedPreferenceChangeListener {
-
- @Override
- public void onSharedPreferenceChanged (SharedPreferences sharedPreferences, String key)
- {
- if (key.startsWith(hack + "_")) {
- if (render != null) {
- boolean was_animating;
- synchronized (render) {
- was_animating = animating_p;
- }
- close();
- if (was_animating)
- start();
- }
- }
- }
- };
-
- private static class SurfaceLost extends Exception {
- SurfaceLost () {
- super("surface lost");
- }
-
- SurfaceLost (String detailMessage) {
- super(detailMessage);
- }
- }
-
- public final static int STYLE_BOLD = 1;
- public final static int STYLE_ITALIC = 2;
- public final static int STYLE_MONOSPACE = 4;
-
- public final static int FONT_FAMILY = 0;
- public final static int FONT_FACE = 1;
- public final static int FONT_RANDOM = 2;
-
- public final static int MY_REQ_READ_EXTERNAL_STORAGE = 271828;
-
- private long nativeRunningHackPtr;
-
- private String hack;
- private Context app;
- private Bitmap screenshot;
-
- SharedPreferences prefs;
- SharedPreferences.OnSharedPreferenceChangeListener pref_listener;
- Hashtable<String, String> defaults = new Hashtable<String, String>();
-
-
- // Maps font names to either: String (system font) or Typeface (bundled).
- private Hashtable<String, Object> all_fonts =
- new Hashtable<String, Object>();
-
- int width, height;
- Surface surface;
- boolean animating_p;
-
- // Doubles as the mutex controlling width/height/animating_p.
- private Thread render;
-
- private Runnable on_quit;
- boolean button_down_p;
-
- // These are defined in jwxyz-android.c:
- //
- private native long nativeInit (String hack,
- Hashtable<String,String> defaults,
- int w, int h, Surface window)
- throws SurfaceLost;
- private native void nativeResize (int w, int h, double rot);
- private native long nativeRender ();
- private native void nativeDone ();
- public native void sendButtonEvent (int x, int y, boolean down);
- public native void sendMotionEvent (int x, int y);
- public native void sendKeyEvent (boolean down_p, int code, int mods);
-
- private void LOG (String fmt, Object... args) {
- Log.d ("xscreensaver", hack + ": " + String.format (fmt, args));
- }
-
- static public String saverNameOf (Object obj) {
- // Extract the saver name from e.g. "gen.Daydream$BouncingCow"
- String name = obj.getClass().getSimpleName();
- int index = name.lastIndexOf('$');
- if (index != -1) {
- index++;
- name = name.substring (index, name.length() - index);
- }
- return name.toLowerCase();
- }
-
- // Constructor
- public jwxyz (String hack, Context app, Bitmap screenshot, int w, int h,
- Surface surface, Runnable on_quit) {
-
- this.hack = hack;
- this.app = app;
- this.screenshot = screenshot;
- this.on_quit = on_quit;
- this.width = w;
- this.height = h;
- this.surface = surface;
-
- // nativeInit populates 'defaults' with the default values for keys
- // that are not overridden by SharedPreferences.
-
- prefs = app.getSharedPreferences (hack, 0);
-
- // Keep a strong reference to pref_listener, because
- // registerOnSharedPreferenceChangeListener only uses a weak reference.
- pref_listener = new PrefListener();
- prefs.registerOnSharedPreferenceChangeListener (pref_listener);
-
- scanSystemFonts();
- }
-
- protected void finalize() {
- if (render != null) {
- LOG ("jwxyz finalized without close. This might be OK.");
- close();
- }
- }
-
-
- public String getStringResource (String name) {
-
- name = hack + "_" + name;
-
- if (prefs.contains(name)) {
-
- // SharedPreferences is very picky that you request the exact type that
- // was stored: if it is a float and you ask for a string, you get an
- // exception instead of the float converted to a string.
-
- String s = null;
- try { return prefs.getString (name, "");
- } catch (Exception e) { }
-
- try { return Float.toString (prefs.getFloat (name, 0));
- } catch (Exception e) { }
-
- try { return Long.toString (prefs.getLong (name, 0));
- } catch (Exception e) { }
-
- try { return Integer.toString (prefs.getInt (name, 0));
- } catch (Exception e) { }
-
- try { return (prefs.getBoolean (name, false) ? "true" : "false");
- } catch (Exception e) { }
- }
-
- // If we got to here, it's not in there, so return the default.
- return defaults.get (name);
- }
-
-
- private String mungeFontName (String name) {
- // Roboto-ThinItalic => RobotoThin
- // AndroidCock Regular => AndroidClock
- String tails[] = { "Bold", "Italic", "Oblique", "Regular" };
- for (String tail : tails) {
- String pres[] = { " ", "-", "_", "" };
- for (String pre : pres) {
- int i = name.indexOf(pre + tail);
- if (i > 0) name = name.substring (0, i);
- }
- }
- return name;
- }
-
-
- private void scanSystemFonts() {
-
- // First parse the system font directories for the global fonts.
-
- String[] fontdirs = { "/system/fonts", "/system/font", "/data/fonts" };
- TTFAnalyzer analyzer = new TTFAnalyzer();
- for (String fontdir : fontdirs) {
- File dir = new File(fontdir);
- if (!dir.exists())
- continue;
- File[] files = dir.listFiles();
- if (files == null)
- continue;
-
- for (File file : files) {
- String name = analyzer.getTtfFontName (file.getAbsolutePath());
- if (name == null) {
- // LOG ("unparsable system font: %s", file);
- } else {
- name = mungeFontName (name);
- if (! all_fonts.contains (name)) {
- // LOG ("system font \"%s\" %s", name, file);
- all_fonts.put (name, name);
- }
- }
- }
- }
-
- // Now parse our assets, for our bundled fonts.
-
- AssetManager am = app.getAssets();
- String dir = "fonts";
- String[] files = null;
- try { files = am.list(dir); }
- catch (Exception e) { LOG("listing assets: %s", e.toString()); }
-
- for (String fn : files) {
- String fn2 = dir + "/" + fn;
- Typeface t = Typeface.createFromAsset (am, fn2);
-
- File tmpfile = null;
- try {
- tmpfile = new File(app.getCacheDir(), fn);
- if (tmpfile.createNewFile() == false) {
- tmpfile.delete();
- tmpfile.createNewFile();
- }
-
- InputStream in = am.open (fn2);
- FileOutputStream out = new FileOutputStream (tmpfile);
- byte[] buffer = new byte[1024 * 512];
- while (in.read(buffer, 0, 1024 * 512) != -1) {
- out.write(buffer);
- }
- out.close();
- in.close();
-
- String name = analyzer.getTtfFontName (tmpfile.getAbsolutePath());
- tmpfile.delete();
-
- name = mungeFontName (name);
- all_fonts.put (name, t);
- // LOG ("asset font \"%s\" %s", name, fn);
- } catch (Exception e) {
- if (tmpfile != null) tmpfile.delete();
- LOG ("error: %s", e.toString());
- }
- }
- }
-
-
- // Parses family names from X Logical Font Descriptions, including a few
- // standard X font names that aren't handled by try_xlfd_font().
- // Returns [ String name, Typeface ]
- private Object[] parseXLFD (int mask, int traits,
- String name, int name_type) {
- boolean fixed = false;
- boolean serif = false;
-
- int style_jwxyz = mask & traits;
-
- if (name_type != FONT_RANDOM) {
- if ((style_jwxyz & STYLE_BOLD) != 0 ||
- name.equals("fixed") ||
- name.equals("courier") ||
- name.equals("console") ||
- name.equals("lucidatypewriter") ||
- name.equals("monospace")) {
- fixed = true;
- } else if (name.equals("times") ||
- name.equals("georgia") ||
- name.equals("serif")) {
- serif = true;
- } else if (name.equals("serif-monospace")) {
- fixed = true;
- serif = true;
- }
- } else {
- Random r = new Random();
- serif = r.nextBoolean(); // Not much to randomize here...
- fixed = (r.nextInt(8) == 0);
- }
-
- name = (fixed
- ? (serif ? "serif-monospace" : "monospace")
- : (serif ? "serif" : "sans-serif"));
-
- int style_android = 0;
- if ((style_jwxyz & STYLE_BOLD) != 0)
- style_android |= Typeface.BOLD;
- if ((style_jwxyz & STYLE_ITALIC) != 0)
- style_android |= Typeface.ITALIC;
-
- return new Object[] { name, Typeface.create(name, style_android) };
- }
-
-
- // Parses "Native Font Name One 12, Native Font Name Two 14".
- // Returns [ String name, Typeface ]
- private Object[] parseNativeFont (String name) {
- Object font2 = all_fonts.get (name);
- if (font2 instanceof String)
- font2 = Typeface.create (name, Typeface.NORMAL);
- return new Object[] { name, (Typeface)font2 };
- }
-
-
- // Returns [ Paint paint, String family_name, Float ascent, Float descent ]
- public Object[] loadFont(int mask, int traits, String name, int name_type,
- float size) {
- Object pair[];
-
- if (name_type != FONT_RANDOM && name.equals("")) return null;
-
- if (name_type == FONT_FACE) {
- pair = parseNativeFont (name);
- } else {
- pair = parseXLFD (mask, traits, name, name_type);
- }
-
- String name2 = (String) pair[0];
- Typeface font = (Typeface) pair[1];
-
- size *= 2;
-
- String suffix = (font.isBold() && font.isItalic() ? " bold italic" :
- font.isBold() ? " bold" :
- font.isItalic() ? " italic" :
- "");
- Paint paint = new Paint();
- paint.setTypeface (font);
- paint.setTextSize (size);
- paint.setColor (Color.argb (0xFF, 0xFF, 0xFF, 0xFF));
-
- LOG ("load font \"%s\" = \"%s %.1f\"", name, name2 + suffix, size);
-
- FontMetrics fm = paint.getFontMetrics();
- return new Object[] { paint, name2, -fm.ascent, fm.descent };
- }
-
-
- /* Returns a byte[] array containing XCharStruct with an optional
- bitmap appended to it.
- lbearing, rbearing, width, ascent, descent: 2 bytes each.
- Followed by a WxH pixmap, 32 bits per pixel.
- */
- public ByteBuffer renderText (Paint paint, String text, boolean render_p,
- boolean antialias_p) {
-
- if (paint == null) {
- LOG ("no font");
- return null;
- }
-
- /* Font metric terminology, as used by X11:
-
- "lbearing" is the distance from the logical origin to the leftmost
- pixel. If a character's ink extends to the left of the origin, it is
- negative.
-
- "rbearing" is the distance from the logical origin to the rightmost
- pixel.
-
- "descent" is the distance from the logical origin to the bottommost
- pixel. For characters with descenders, it is positive. For
- superscripts, it is negative.
-
- "ascent" is the distance from the logical origin to the topmost pixel.
- It is the number of pixels above the baseline.
-
- "width" is the distance from the logical origin to the position where
- the logical origin of the next character should be placed.
-
- If "rbearing" is greater than "width", then this character overlaps the
- following character. If smaller, then there is trailing blank space.
-
- The bbox coordinates returned by getTextBounds grow down and right:
- for a character with ink both above and below the baseline, top is
- negative and bottom is positive.
- */
- paint.setAntiAlias (antialias_p);
- FontMetrics fm = paint.getFontMetrics();
- Rect bbox = new Rect();
- paint.getTextBounds (text, 0, text.length(), bbox);
-
- /* The bbox returned by getTextBounds measures from the logical origin
- with right and down being positive. This means most characters have
- a negative top, and characters with descenders have a positive bottom.
- */
- int lbearing = bbox.left;
- int rbearing = bbox.right;
- int ascent = -bbox.top;
- int descent = bbox.bottom;
- int width = (int) paint.measureText (text);
-
- int w = rbearing - lbearing;
- int h = ascent + descent;
- int size = 5 * 2 + (render_p ? w * h * 4 : 0);
-
- ByteBuffer bits = ByteBuffer.allocateDirect (size);
-
- bits.put ((byte) ((lbearing >> 8) & 0xFF));
- bits.put ((byte) ( lbearing & 0xFF));
- bits.put ((byte) ((rbearing >> 8) & 0xFF));
- bits.put ((byte) ( rbearing & 0xFF));
- bits.put ((byte) ((width >> 8) & 0xFF));
- bits.put ((byte) ( width & 0xFF));
- bits.put ((byte) ((ascent >> 8) & 0xFF));
- bits.put ((byte) ( ascent & 0xFF));
- bits.put ((byte) ((descent >> 8) & 0xFF));
- bits.put ((byte) ( descent & 0xFF));
-
- if (render_p && w > 0 && h > 0) {
- Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas (bitmap);
- canvas.drawText (text, -lbearing, ascent, paint);
- bitmap.copyPixelsToBuffer (bits);
- bitmap.recycle();
- }
-
- return bits;
- }
-
-
- /* Returns the contents of the URL.
- Loads the URL in a background thread: if the URL has not yet loaded,
- this will return null. Once the URL has completely loaded, the full
- contents will be returned. Calling this again after that starts the
- URL loading again.
- */
- private String loading_url = null;
- private ByteBuffer loaded_url_body = null;
-
- public synchronized ByteBuffer loadURL (String url) {
-
- if (loaded_url_body != null) { // Thread finished
-
- // LOG ("textclient finished %s", loading_url);
-
- ByteBuffer bb = loaded_url_body;
- loading_url = null;
- loaded_url_body = null;
- return bb;
-
- } else if (loading_url != null) { // Waiting on thread
- // LOG ("textclient waiting...");
- return null;
-
- } else { // Launch thread
-
- loading_url = url;
- LOG ("textclient launching %s...", url);
-
- new Thread (new Runnable() {
- public void run() {
- int size0 = 10240;
- int size = size0;
- int count = 0;
- ByteBuffer body = ByteBuffer.allocateDirect (size);
-
- try {
- URL u = new URL (loading_url);
- // LOG ("textclient thread loading: %s", u.toString());
- InputStream s = u.openStream();
- byte buf[] = new byte[10240];
- while (true) {
- int n = s.read (buf);
- if (n == -1) break;
- // LOG ("textclient thread read %d", n);
- if (count + n + 1 >= size) {
- int size2 = (int) (size * 1.2 + size0);
- // LOG ("textclient thread expand %d -> %d", size, size2);
- ByteBuffer body2 = ByteBuffer.allocateDirect (size2);
- body.rewind();
- body2.put (body);
- body2.position (count);
- body = body2;
- size = size2;
- }
- body.put (buf, 0, n);
- count += n;
- }
- } catch (Exception e) {
- LOG ("load URL error: %s", e.toString());
- body.clear();
- body.put (e.toString().getBytes());
- body.put ((byte) 0);
- }
-
- // LOG ("textclient thread finished %s (%d)", loading_url, size);
- loaded_url_body = body;
- }
- }).start();
-
- return null;
- }
- }
-
-
- // Returns [ Bitmap bitmap, String name ]
- private Object[] convertBitmap (String name, Bitmap bitmap,
- int target_width, int target_height,
- ExifInterface exif, boolean rotate_p) {
- if (bitmap == null) return null;
-
- {
-
- int width = bitmap.getWidth();
- int height = bitmap.getHeight();
- Matrix matrix = new Matrix();
-
- LOG ("read image %s: %d x %d", name, width, height);
-
- // First rotate the image as per EXIF.
-
- if (exif != null) {
- int deg = 0;
- switch (exif.getAttributeInt (ExifInterface.TAG_ORIENTATION,
- ExifInterface.ORIENTATION_NORMAL)) {
- case ExifInterface.ORIENTATION_ROTATE_90: deg = 90; break;
- case ExifInterface.ORIENTATION_ROTATE_180: deg = 180; break;
- case ExifInterface.ORIENTATION_ROTATE_270: deg = 270; break;
- }
- if (deg != 0) {
- LOG ("%s: EXIF rotate %d", name, deg);
- matrix.preRotate (deg);
- if (deg == 90 || deg == 270) {
- int temp = width;
- width = height;
- height = temp;
- }
- }
- }
-
- // If the caller requested that we rotate the image to best fit the
- // screen, rotate it again.
-
- if (rotate_p &&
- (width > height) != (target_width > target_height)) {
- LOG ("%s: rotated to fit screen", name);
- matrix.preRotate (90);
-
- int temp = width;
- width = height;
- height = temp;
- }
-
- // Resize the image to be not larger than the screen, potentially
- // copying it for the third time.
- // Actually, always scale it, scaling up if necessary.
-
-// if (width > target_width || height > target_height)
- {
- float r1 = target_width / (float) width;
- float r2 = target_height / (float) height;
- float r = (r1 > r2 ? r2 : r1);
- LOG ("%s: resize %.1f: %d x %d => %d x %d", name,
- r, width, height, (int) (width * r), (int) (height * r));
- matrix.preScale (r, r);
- }
-
- bitmap = Bitmap.createBitmap (bitmap, 0, 0,
- bitmap.getWidth(), bitmap.getHeight(),
- matrix, true);
-
- if (bitmap.getConfig() != Bitmap.Config.ARGB_8888)
- bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, false);
-
- return new Object[] { bitmap, name };
-
- }
- }
-
-
- boolean havePermission(String permission) {
-
- if (Build.VERSION.SDK_INT < 16) {
- return true;
- }
-
- if (permissionGranted(permission)) {
- return true;
- }
-
- return false;
- }
-
-
- private boolean permissionGranted(String permission) {
- boolean check = ContextCompat.checkSelfPermission(app, permission) ==
- PackageManager.PERMISSION_GRANTED;
- return check;
- }
-
- public Object[] checkThenLoadRandomImage (int target_width, int target_height,
- boolean rotate_p) {
- // RES introduced in API 16
- String permission = Manifest.permission.READ_EXTERNAL_STORAGE;
-
- if (havePermission(permission)) {
- return loadRandomImage(target_width,target_height,rotate_p);
- } else {
- return null;
- }
- }
-
- public Object[] loadRandomImage (int target_width, int target_height,
- boolean rotate_p) {
-
- int min_size = 480;
- int max_size = 0x7FFF;
-
- ArrayList<String> imgs = new ArrayList<String>();
-
- ContentResolver cr = app.getContentResolver();
- String[] cols = { MediaColumns.DATA,
- MediaColumns.MIME_TYPE,
- MediaColumns.WIDTH,
- MediaColumns.HEIGHT };
- Uri uris[] = {
- android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI,
- android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI };
-
- for (int i = 0; i < uris.length; i++) {
- Cursor cursor = cr.query (uris[i], cols, null, null, null);
- if (cursor == null)
- continue;
- int j = 0;
- int path_col = cursor.getColumnIndexOrThrow (cols[j++]);
- int type_col = cursor.getColumnIndexOrThrow (cols[j++]);
- int width_col = cursor.getColumnIndexOrThrow (cols[j++]);
- int height_col = cursor.getColumnIndexOrThrow (cols[j++]);
- while (cursor.moveToNext()) {
- String path = cursor.getString(path_col);
- String type = cursor.getString(type_col);
- if (path != null && type != null && type.startsWith("image/")) {
- String wc = cursor.getString(width_col);
- String hc = cursor.getString(height_col);
- if (wc != null && hc != null) {
- int w = Integer.parseInt (wc);
- int h = Integer.parseInt (hc);
- if (w > min_size && h > min_size &&
- w < max_size && h < max_size) {
- imgs.add (path);
- }
- }
- }
- }
- cursor.close();
- }
-
- String which = null;
-
- int count = imgs.size();
- if (count == 0) {
- LOG ("no images");
- return null;
- }
-
- int i = new Random().nextInt (count);
- which = imgs.get (i);
- LOG ("picked image %d of %d: %s", i, count, which);
-
- Uri uri = Uri.fromFile (new File (which));
- String name = uri.getLastPathSegment();
- Bitmap bitmap = null;
- ExifInterface exif = null;
-
- try {
- try {
- bitmap = MediaStore.Images.Media.getBitmap (cr, uri);
- } catch (Exception e) {
- LOG ("image %s unloadable: %s", which, e.toString());
- return null;
- }
-
- try {
- exif = new ExifInterface (uri.getPath()); // If it fails, who cares
- } catch (Exception e) {
- }
-
- return convertBitmap (name, bitmap, target_width, target_height,
- exif, rotate_p);
- } catch (java.lang.OutOfMemoryError e) {
- LOG ("image %s got OutOfMemoryError: %s", which, e.toString());
- return null;
- }
- }
-
-
- public Object[] getScreenshot (int target_width, int target_height,
- boolean rotate_p) {
- return convertBitmap ("Screenshot", screenshot,
- target_width, target_height,
- null, rotate_p);
- }
-
-
- public Bitmap decodePNG (byte[] data) {
- BitmapFactory.Options opts = new BitmapFactory.Options();
- opts.inPreferredConfig = Bitmap.Config.ARGB_8888;
- return BitmapFactory.decodeByteArray (data, 0, data.length, opts);
- }
-
-
- // Sadly duplicated from jwxyz.h (and thence X.h and keysymdef.h)
- //
- private static final int ShiftMask = (1<<0);
- private static final int LockMask = (1<<1);
- private static final int ControlMask = (1<<2);
- private static final int Mod1Mask = (1<<3);
- private static final int Mod2Mask = (1<<4);
- private static final int Mod3Mask = (1<<5);
- private static final int Mod4Mask = (1<<6);
- private static final int Mod5Mask = (1<<7);
- private static final int Button1Mask = (1<<8);
- private static final int Button2Mask = (1<<9);
- private static final int Button3Mask = (1<<10);
- private static final int Button4Mask = (1<<11);
- private static final int Button5Mask = (1<<12);
-
- private static final int XK_Shift_L = 0xFFE1;
- private static final int XK_Shift_R = 0xFFE2;
- private static final int XK_Control_L = 0xFFE3;
- private static final int XK_Control_R = 0xFFE4;
- private static final int XK_Caps_Lock = 0xFFE5;
- private static final int XK_Shift_Lock = 0xFFE6;
- private static final int XK_Meta_L = 0xFFE7;
- private static final int XK_Meta_R = 0xFFE8;
- private static final int XK_Alt_L = 0xFFE9;
- private static final int XK_Alt_R = 0xFFEA;
- private static final int XK_Super_L = 0xFFEB;
- private static final int XK_Super_R = 0xFFEC;
- private static final int XK_Hyper_L = 0xFFED;
- private static final int XK_Hyper_R = 0xFFEE;
-
- private static final int XK_Home = 0xFF50;
- private static final int XK_Left = 0xFF51;
- private static final int XK_Up = 0xFF52;
- private static final int XK_Right = 0xFF53;
- private static final int XK_Down = 0xFF54;
- private static final int XK_Prior = 0xFF55;
- private static final int XK_Page_Up = 0xFF55;
- private static final int XK_Next = 0xFF56;
- private static final int XK_Page_Down = 0xFF56;
- private static final int XK_End = 0xFF57;
- private static final int XK_Begin = 0xFF58;
-
- private static final int XK_F1 = 0xFFBE;
- private static final int XK_F2 = 0xFFBF;
- private static final int XK_F3 = 0xFFC0;
- private static final int XK_F4 = 0xFFC1;
- private static final int XK_F5 = 0xFFC2;
- private static final int XK_F6 = 0xFFC3;
- private static final int XK_F7 = 0xFFC4;
- private static final int XK_F8 = 0xFFC5;
- private static final int XK_F9 = 0xFFC6;
- private static final int XK_F10 = 0xFFC7;
- private static final int XK_F11 = 0xFFC8;
- private static final int XK_F12 = 0xFFC9;
-
- public void sendKeyEvent (KeyEvent event) {
- int uc = event.getUnicodeChar();
- int jcode = event.getKeyCode();
- int jmods = event.getModifiers();
- int xcode = 0;
- int xmods = 0;
-
- switch (jcode) {
- case KeyEvent.KEYCODE_SHIFT_LEFT: xcode = XK_Shift_L; break;
- case KeyEvent.KEYCODE_SHIFT_RIGHT: xcode = XK_Shift_R; break;
- case KeyEvent.KEYCODE_CTRL_LEFT: xcode = XK_Control_L; break;
- case KeyEvent.KEYCODE_CTRL_RIGHT: xcode = XK_Control_R; break;
- case KeyEvent.KEYCODE_CAPS_LOCK: xcode = XK_Caps_Lock; break;
- case KeyEvent.KEYCODE_META_LEFT: xcode = XK_Meta_L; break;
- case KeyEvent.KEYCODE_META_RIGHT: xcode = XK_Meta_R; break;
- case KeyEvent.KEYCODE_ALT_LEFT: xcode = XK_Alt_L; break;
- case KeyEvent.KEYCODE_ALT_RIGHT: xcode = XK_Alt_R; break;
-
- case KeyEvent.KEYCODE_HOME: xcode = XK_Home; break;
- case KeyEvent.KEYCODE_DPAD_LEFT: xcode = XK_Left; break;
- case KeyEvent.KEYCODE_DPAD_UP: xcode = XK_Up; break;
- case KeyEvent.KEYCODE_DPAD_RIGHT: xcode = XK_Right; break;
- case KeyEvent.KEYCODE_DPAD_DOWN: xcode = XK_Down; break;
- //case KeyEvent.KEYCODE_NAVIGATE_PREVIOUS: xcode = XK_Prior; break;
- case KeyEvent.KEYCODE_PAGE_UP: xcode = XK_Page_Up; break;
- //case KeyEvent.KEYCODE_NAVIGATE_NEXT: xcode = XK_Next; break;
- case KeyEvent.KEYCODE_PAGE_DOWN: xcode = XK_Page_Down; break;
- case KeyEvent.KEYCODE_MOVE_END: xcode = XK_End; break;
- case KeyEvent.KEYCODE_MOVE_HOME: xcode = XK_Begin; break;
-
- case KeyEvent.KEYCODE_F1: xcode = XK_F1; break;
- case KeyEvent.KEYCODE_F2: xcode = XK_F2; break;
- case KeyEvent.KEYCODE_F3: xcode = XK_F3; break;
- case KeyEvent.KEYCODE_F4: xcode = XK_F4; break;
- case KeyEvent.KEYCODE_F5: xcode = XK_F5; break;
- case KeyEvent.KEYCODE_F6: xcode = XK_F6; break;
- case KeyEvent.KEYCODE_F7: xcode = XK_F7; break;
- case KeyEvent.KEYCODE_F8: xcode = XK_F8; break;
- case KeyEvent.KEYCODE_F9: xcode = XK_F9; break;
- case KeyEvent.KEYCODE_F10: xcode = XK_F10; break;
- case KeyEvent.KEYCODE_F11: xcode = XK_F11; break;
- case KeyEvent.KEYCODE_F12: xcode = XK_F12; break;
- default: xcode = uc; break;
- }
-
- if (0 != (jmods & KeyEvent.META_SHIFT_ON)) xmods |= ShiftMask;
- if (0 != (jmods & KeyEvent.META_CAPS_LOCK_ON)) xmods |= LockMask;
- if (0 != (jmods & KeyEvent.META_CTRL_MASK)) xmods |= ControlMask;
- if (0 != (jmods & KeyEvent.META_ALT_MASK)) xmods |= Mod1Mask;
- if (0 != (jmods & KeyEvent.META_META_ON)) xmods |= Mod1Mask;
- if (0 != (jmods & KeyEvent.META_SYM_ON)) xmods |= Mod2Mask;
- if (0 != (jmods & KeyEvent.META_FUNCTION_ON)) xmods |= Mod3Mask;
-
- /* If you touch and release Shift, you get no events.
- If you type Shift-A, you get Shift down, A down, A up, Shift up.
- So let's just ignore all lone modifier key events.
- */
- if (xcode >= XK_Shift_L && xcode <= XK_Hyper_R)
- return;
-
- boolean down_p = event.getAction() == KeyEvent.ACTION_DOWN;
- sendKeyEvent (down_p, xcode, xmods);
- }
-
- void start () {
- if (render == null) {
- animating_p = true;
- render = new Thread(new Runnable() {
- @Override
- public void run()
- {
- int currentWidth, currentHeight;
- synchronized (render) {
- while (true) {
- while (!animating_p || width == 0 || height == 0) {
- try {
- render.wait();
- } catch(InterruptedException exc) {
- return;
- }
- }
-
- try {
- nativeInit (hack, defaults, width, height, surface);
- currentWidth = width;
- currentHeight= height;
- break;
- } catch (SurfaceLost exc) {
- width = 0;
- height = 0;
- }
- }
- }
-
- main_loop:
- while (true) {
- synchronized (render) {
- assert width != 0;
- assert height != 0;
- while (!animating_p) {
- try {
- render.wait();
- } catch(InterruptedException exc) {
- break main_loop;
- }
- }
-
- if (currentWidth != width || currentHeight != height) {
- currentWidth = width;
- currentHeight = height;
- nativeResize (width, height, 0);
- }
- }
-
- long delay = nativeRender();
-
- synchronized (render) {
- if (delay != 0) {
- try {
- render.wait(delay / 1000, (int)(delay % 1000) * 1000);
- } catch (InterruptedException exc) {
- break main_loop;
- }
- } else {
- if (Thread.interrupted ()) {
- break main_loop;
- }
- }
- }
- }
-
- assert nativeRunningHackPtr != 0;
- nativeDone ();
- }
- });
-
- render.start();
- } else {
- synchronized(render) {
- animating_p = true;
- render.notify();
- }
- }
- }
-
- void pause () {
- if (render == null)
- return;
- synchronized (render) {
- animating_p = false;
- render.notify();
- }
- }
-
- void close () {
- if (render == null)
- return;
- synchronized (render) {
- animating_p = false;
- render.interrupt();
- }
- try {
- render.join();
- } catch (InterruptedException exc) {
- }
- render = null;
- }
-
- void resize (int w, int h) {
- assert w != 0;
- assert h != 0;
- if (render != null) {
- synchronized (render) {
- width = w;
- height = h;
- render.notify();
- }
- } else {
- width = w;
- height = h;
- }
- }
-
-
- /* We distinguish between taps and drags.
-
- - Drags/pans (down, motion, up) are sent to the saver to handle.
- - Single-taps exit the saver.
- - Long-press single-taps are sent to the saver as ButtonPress/Release;
- - Double-taps are sent to the saver as a "Space" keypress.
-
- #### TODO:
- - Swipes (really, two-finger drags/pans) send Up/Down/Left/RightArrow.
- */
-
- @Override
- public boolean onSingleTapConfirmed (MotionEvent event) {
- if (on_quit != null)
- on_quit.run();
- return true;
- }
-
- @Override
- public boolean onDoubleTap (MotionEvent event) {
- sendKeyEvent (new KeyEvent (KeyEvent.ACTION_DOWN,
- KeyEvent.KEYCODE_SPACE));
- return true;
- }
-
- @Override
- public void onLongPress (MotionEvent event) {
- if (! button_down_p) {
- int x = (int) event.getX (event.getPointerId (0));
- int y = (int) event.getY (event.getPointerId (0));
- sendButtonEvent (x, y, true);
- sendButtonEvent (x, y, false);
- }
- }
-
- @Override
- public void onShowPress (MotionEvent event) {
- if (! button_down_p) {
- button_down_p = true;
- int x = (int) event.getX (event.getPointerId (0));
- int y = (int) event.getY (event.getPointerId (0));
- sendButtonEvent (x, y, true);
- }
- }
-
- @Override
- public boolean onScroll (MotionEvent e1, MotionEvent e2,
- float distanceX, float distanceY) {
- // LOG ("onScroll: %d", button_down_p ? 1 : 0);
- if (button_down_p)
- sendMotionEvent ((int) e2.getX (e2.getPointerId (0)),
- (int) e2.getY (e2.getPointerId (0)));
- return true;
- }
-
- // If you drag too fast, you get a single onFling event instead of a
- // succession of onScroll events. I can't figure out how to disable it.
- @Override
- public boolean onFling (MotionEvent e1, MotionEvent e2,
- float velocityX, float velocityY) {
- return false;
- }
-
- public boolean dragEnded (MotionEvent event) {
- if (button_down_p) {
- int x = (int) event.getX (event.getPointerId (0));
- int y = (int) event.getY (event.getPointerId (0));
- sendButtonEvent (x, y, false);
- button_down_p = false;
- }
- return true;
- }
-
- @Override
- public boolean onDown (MotionEvent event) {
- return false;
- }
-
- @Override
- public boolean onSingleTapUp (MotionEvent event) {
- return false;
- }
-
- @Override
- public boolean onDoubleTapEvent (MotionEvent event) {
- return false;
- }
-
-
- static {
- System.loadLibrary ("xscreensaver");
-
-/*
- Thread.setDefaultUncaughtExceptionHandler(
- new Thread.UncaughtExceptionHandler() {
- Thread.UncaughtExceptionHandler old_handler =
- Thread.currentThread().getUncaughtExceptionHandler();
-
- @Override
- public void uncaughtException (Thread thread, Throwable ex) {
- String err = ex.toString();
- Log.d ("xscreensaver", "Caught exception: " + err);
- old_handler.uncaughtException (thread, ex);
- }
- });
-*/
- }
-}