From 67847892c023174a0f4771a473196e85945b73c7 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Tue, 30 Jul 2019 16:02:49 +0200 Subject: Remove android and OSX files --- .../src/org/jwz/xscreensaver/Activity.java | 169 --- .../xscreensaver/src/org/jwz/xscreensaver/App.java | 22 - .../src/org/jwz/xscreensaver/Daydream.java | 269 ----- .../src/org/jwz/xscreensaver/Settings.java | 179 ---- .../src/org/jwz/xscreensaver/SliderPreference.java | 160 --- .../src/org/jwz/xscreensaver/TTFAnalyzer.java | 153 --- .../src/org/jwz/xscreensaver/TVActivity.java | 50 - .../src/org/jwz/xscreensaver/Wallpaper.java | 128 --- .../src/org/jwz/xscreensaver/jwxyz.java | 1115 -------------------- 9 files changed, 2245 deletions(-) delete mode 100644 android/xscreensaver/src/org/jwz/xscreensaver/Activity.java delete mode 100644 android/xscreensaver/src/org/jwz/xscreensaver/App.java delete mode 100644 android/xscreensaver/src/org/jwz/xscreensaver/Daydream.java delete mode 100644 android/xscreensaver/src/org/jwz/xscreensaver/Settings.java delete mode 100644 android/xscreensaver/src/org/jwz/xscreensaver/SliderPreference.java delete mode 100644 android/xscreensaver/src/org/jwz/xscreensaver/TTFAnalyzer.java delete mode 100644 android/xscreensaver/src/org/jwz/xscreensaver/TVActivity.java delete mode 100644 android/xscreensaver/src/org/jwz/xscreensaver/Wallpaper.java delete mode 100644 android/xscreensaver/src/org/jwz/xscreensaver/jwxyz.java (limited to 'android/xscreensaver/src/org/jwz') 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 - * and Dennis Sheil - * - * 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 - * and Dennis Sheil - * - * 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 - * - * 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 - * and Dennis Sheil - * - * 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 keys = prefs.getAll(); - for (Map.Entry 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 keys = prefs.getAll(); - for (Map.Entry 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 - * - * 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 "" 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 - * and Dennis Sheil - * - * 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 - * - * 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 - * - * 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 defaults = new Hashtable(); - - - // Maps font names to either: String (system font) or Typeface (bundled). - private Hashtable all_fonts = - new Hashtable(); - - 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 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 imgs = new ArrayList(); - - 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); - } - }); -*/ - } -} -- cgit v1.2.3-55-g7522