/* Copyright 2010 Hugh Greenberg */
package com.hugegreenbug.msoss;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Random;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;
import android.R.drawable;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Process;
import android.os.SystemClock;
import android.provider.MediaStore;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import com.hugegreenbug.msoss.R;
import com.hugegreenbug.msoss.Cube;
import com.rbgrn.net.GLWallpaperService;
public class Ms extends GLWallpaperService {
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public Engine onCreateEngine() {
return new msEngine();
}
class msEngine extends GLEngine implements SharedPreferences.OnSharedPreferenceChangeListener {
public static final String SHARED_PREFS_NAME="mssettings";
public static final String WIKI_COMMONS_BASE="http://commons.wikimedia.org";
private static final long ERROR_RECOVER = 5000; //Milliseconds to restart download for a recoverable failure
private static final long ERROR_STD = 300000; //Milliseconds to restart download for a serious error
private static final int ERROR_MAX_RETRIES = 20; //Maximum number of retries before stopping downloads for a while
private static final int GET_IMAGE = 1;
private static final String CUSTOM_BG_FILE="background.png";
private DefaultHttpClient client;
private SharedPreferences mPrefs;
private volatile boolean mVisible;
private volatile WikiCommonsImage curWikiImage;
private ArrayList<String> mNotFound = new ArrayList<String>();
private int MAX_NOT_FOUND = 50;
private volatile long mScheduledUpdate;
private final float mThresh = 0.2f;
private int mRetries;
private volatile String mSelection;
private volatile boolean mFull;
private volatile int mRefreshRate;
private volatile boolean mSettingWikiImage;
private volatile boolean mGettingWikiImage;
private volatile boolean mDestroyed;
private volatile boolean mSettingPreferences;
private volatile boolean mImageViewed;
private volatile boolean mSkipArtist;
private int mNumTaps;
private long mLastTouch;
private float mFirstTouchX;
private float mFirstTouchY;
private volatile MsRenderer mRenderer;
private Cube mCube;
private Wall mWall;
private volatile boolean mFirstImage;
private volatile boolean mRefreshGesture;
private volatile Background mBackground;
private volatile boolean mSettingBg;
private volatile String mCubeBg;
private volatile String mCubeCustomBg;
private NotificationManager mNotifyMan;
private ImageScheduler mImageScheduler;
private final Runnable mGetImage = new Runnable() {
public void run() {
getImage();
}
};
msEngine() {
super();
client = null;
mRenderer = new MsRenderer();
mCube = new Cube();
mWall = new Wall();
mBackground = new Background();
mRenderer.setCube(mCube);
mRenderer.setWall(mWall);
mRenderer.setBackground(mBackground);
mPrefs = getSharedPreferences(SHARED_PREFS_NAME, 0);
mPrefs.registerOnSharedPreferenceChangeListener(this);
//onSharedPreferenceChanged(mPrefs, null);
SharedPreferences.Editor editor = mPrefs.edit();
mSelection = mPrefs.getString("ms_image_select", "best");
mFull = mPrefs.getBoolean("ms_image_full", false);
try {
String rate = mPrefs.getString("ms_refresh_rate", "3");
mRefreshRate = Integer.parseInt(rate) * 60;
if (mRefreshRate < 60 || mRefreshRate > 1440) {
mRefreshRate = 60;
editor.putString("ms_refresh_rate", "1");
}
} catch (NumberFormatException nfe) {
mRefreshRate = 60;
editor.putString("ms_refresh_rate", "1");
}
mNotifyMan = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mRenderer.setCubeScale(mPrefs.getBoolean("ms_cube_scale", true));
mRenderer.setDisplayArtistImage(mPrefs.getBoolean("ms_display_artist", true));
mRenderer.setDisplayArtistVisible(mPrefs.getBoolean("ms_display_artist_visible", false));
mSkipArtist = mPrefs.getBoolean("ms_artist_skip", true);
setImageDisplay(mPrefs.getString("ms_image_display", "cube"));
mCubeBg = mPrefs.getString("ms_cube_bg", "default_bg");
mCubeCustomBg = mPrefs.getString("ms_custom_background_uri", "unknown");
mRenderer.setStretchBg(mPrefs.getBoolean("ms_cubebg_stretch", true));
mRenderer.setStretchWall(mPrefs.getBoolean("ms_wall_stretch", true));
try {
String cc = (mPrefs.getString("ms_cube_color", "0"));
int color = Integer.parseInt(cc);
mRenderer.setClearColor(color);
} catch (NumberFormatException nfe) {
mRenderer.setClearColor(0);
editor.putString("ms_cube_color", "0");
}
int textColor = -1;
try {
String color = mPrefs.getString("ms_text_color", "-1");
textColor = Integer.parseInt(color);
} catch (NumberFormatException nfe) {
textColor = -1;
editor.putString("ms_image_display", "-1");
}
mRenderer.setTextColor(textColor);
float newTextSize = 40.0f;
try {
String textSize = mPrefs.getString("ms_artist_text_size", "40.0");
newTextSize = Float.parseFloat(textSize);
if (newTextSize < 20.0f || newTextSize > 100.0f)
newTextSize = 40.0f;
} catch (NumberFormatException nfe) {
newTextSize = 40.0f;
editor.putString("ms_artist_text_size", "40.0");
}
mVisible = true;
mRenderer.setTextSize(newTextSize);
mFirstImage = true;
mRefreshGesture = false;
curWikiImage = null;
mScheduledUpdate = System.currentTimeMillis() + mRefreshRate * 60 * 1000;
mSettingWikiImage = false;
mGettingWikiImage = false;
mSettingPreferences = false;
mDestroyed = false;
mImageViewed = false;
mNumTaps = 0;
mLastTouch = 0;
mSettingBg = false;
mRetries = 0;
editor.commit();
setRenderer(mRenderer);
setRenderMode(RENDERMODE_CONTINUOUSLY);
mImageScheduler = new ImageScheduler(mGetImage);
updateImageHandlerMills(200); //Start the first image download
}
public void setImageDisplay(String imageDisplay) {
if (imageDisplay.equals("cube"))
mRenderer.setImageDisplay(MsRenderer.CUBE_MODE);
else if (imageDisplay.equals("wall"))
mRenderer.setImageDisplay(MsRenderer.WALL_MODE);
else
mRenderer.setImageDisplay(MsRenderer.ZOOM_MODE);
}
public void updateStorageState(boolean state) {
if (state) {
updateImageHandlerDiff();
}
}
public void setBackground(boolean custBgChange) {
while (mSettingWikiImage) {
SystemClock.sleep(100);
}
mSettingBg = true;
mBackground.setByteBuffer(null);
Bitmap bmap = null;
//int maxTexSize = mRenderer.getMaxTexSize();
int canvasWidth = mRenderer.getCanvasWidth();
int canvasHeight = mRenderer.getCanvasHeight();
int origWidth, origHeight;
try {
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inJustDecodeBounds = true;
float wr = 1.0f;
float hr = 1.0f;
System.gc();
if (mCubeBg.equals("default_bg")) {
BitmapFactory.decodeResource(getResources(), R.drawable.default_bg, opt);
origWidth = opt.outWidth;
origHeight = opt.outHeight;
wr = (float) origWidth/canvasWidth;
hr = (float) origHeight/canvasHeight;
opt.inJustDecodeBounds = false;
opt.inSampleSize = (int) Math.ceil(Math.min(wr, hr));
bmap = BitmapFactory.decodeResource(getResources(), R.drawable.default_bg, opt);
} else if (mCubeBg.equals("custom_background") && !mCubeCustomBg.equals("unknown")) {
if (custBgChange) {
File newBg = new File(mCubeCustomBg);
if (newBg.exists())
BitmapFactory.decodeFile(mCubeCustomBg, opt);
else
opt = null;
} else {
try {
FileInputStream fis = openFileInput(CUSTOM_BG_FILE);
BitmapFactory.decodeStream(fis, null, opt);
fis.close();
} catch (FileNotFoundException fne) {
File newBg = new File(mCubeCustomBg);
if (newBg.exists()) {
BitmapFactory.decodeFile(mCubeCustomBg, opt);
custBgChange = true;
} else
opt = null;
} catch (IOException e) {
opt = null;
}
}
if (opt != null) {
origWidth = opt.outWidth;
origHeight = opt.outHeight;
opt.inJustDecodeBounds = false;
if (custBgChange) {
wr = (float) origWidth/canvasWidth;
hr = (float) origHeight/canvasHeight;
opt.inSampleSize = (int) Math.ceil(Math.min(wr, hr));
bmap = BitmapFactory.decodeFile(mCubeCustomBg, opt);
FileOutputStream fos;
try {
fos = openFileOutput(CUSTOM_BG_FILE, Context.MODE_PRIVATE);
if (bmap != null)
bmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.close();
} catch (FileNotFoundException e) {
Log.e("Musician Slideshow", "File not found error while writing custom background to app dir");
} catch (IOException e) {
Log.e("Musician Slideshow", "I/O error while writing custom background to app dir");
}
} else {
try {
opt.inSampleSize = 0;
FileInputStream fis = openFileInput(CUSTOM_BG_FILE);
bmap = BitmapFactory.decodeStream(fis, null, opt);
fis.close();
} catch (FileNotFoundException fne) {
Log.e("Musician Slideshow", "File not found error while writing custom background to app dir");
} catch (IOException e) {
Log.e("Musician Slideshow", "I/O error while writing custom background to app dir");
}
}
}
} else {
mSettingBg = false;
return;
}
} catch (OutOfMemoryError ome) {
Log.e("Musician Slideshow", "Out of memory error while creating bmap for bg: "
+ mCubeBg + " error: " + ome.getMessage());
mSettingBg = false;
return;
}
if (bmap != null)
scaleBmap(bmap, mBackground);
System.gc();
mRenderer.setClearColor();
mSettingBg = false;
}
public void setPreviewImage() {
if (!isPreview())
return;
try {
mFirstImage = false;
WikiCommonsImage newWikiImage = new WikiCommonsImage();
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(),
R.drawable.preview_image, opt);
float wr = (float) opt.outWidth/mRenderer.getCanvasWidth();
float hr = (float) opt.outHeight/mRenderer.getCanvasHeight();
int ssample = (int) Math.ceil(Math.min(wr, hr));
opt.inJustDecodeBounds = false;
opt.inSampleSize = ssample;
System.gc();
Bitmap tempBmap = BitmapFactory.decodeResource(getResources(),
R.drawable.preview_image, opt);
Background bg = scaleBmap(tempBmap, newWikiImage);
if (bg != null) {
newWikiImage.setText(new String[] {"Musician", "Slideshow"});
curWikiImage = newWikiImage;
newWikiImage = null;
mRenderer.setFadeIn(MsRenderer.MAX_FADEOUT);
mRenderer.setFadeOut(MsRenderer.MAX_FADEOUT);
mRenderer.setCurWikiImage(curWikiImage);
}
} catch (OutOfMemoryError ome) {
Log.e("Musician Slideshow", "Out of memory while loading preview image");
}
}
public synchronized void getImage() {
if (mDestroyed)
return;
mGettingWikiImage = true;
mImageScheduler.cancelNextRun();
mRenderer.setError(MsRenderer.ERROR_NOERROR);
while ((mFirstImage && (mRenderer == null || mRenderer.getCanvasWidth() == 0 ||
mRenderer.getCanvasHeight() == 0 ||
mRenderer.getCanvasWidthThresh() == 0 ||
mRenderer.getCanvasHeightThresh() == 0)) || mSettingPreferences) {
SystemClock.sleep(100);
}
if (isPreview()) {
setPreviewImage();
mGettingWikiImage = false;
return;
}
if (mRenderer.getImageDisplay() == MsRenderer.CUBE_MODE && !mCubeBg.equals("none") &&
mBackground.getByteBuffer() == null && mFirstImage) {
mRenderer.settingBackground(true);
mRenderer.setRelease(MsRenderer.RELEASE_WALL_TEX);
setBackground(false);
mRenderer.setNewBg();
mRenderer.settingBackground(false);
} else if (mRenderer.getImageDisplay() == MsRenderer.CUBE_MODE && mCubeBg.equals("none") &&
mFirstImage)
mRenderer.setClearColor();
Process.setThreadPriority(Process.THREAD_PRIORITY_LOWEST);
String curArtist = null;
if (client == null) {
client = new DefaultHttpClient();
}
ArrayList<WikiCommonsThumb> thumbs = null;
float canvasRatio = mRenderer.getCanvasRatio();
int canvasWidth = mRenderer.getCanvasWidth();
int canvasHeight = mRenderer.getCanvasHeight();
double canvasWidthThresh = mRenderer.getCanvasWidthThresh();
double canvasHeightThresh = mRenderer.getCanvasHeightThresh();
ImageFinderHandler imgFindHand = new ImageFinderHandler(canvasRatio);
XMLReader xr = null;
try {
System.setProperty("org.xml.sax.driver","org.xmlpull.v1.sax2.Driver");
xr = XMLReaderFactory.createXMLReader();
xr.setContentHandler(imgFindHand);
xr.setErrorHandler(imgFindHand);
} catch (SAXException e) {
handleGetImageError(false);
return;
}
while (curArtist == null) {
ContentResolver res = getBaseContext().getContentResolver();
Cursor extCur = res.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
new String[] {"ARTIST"}, null, null, "RANDOM() LIMIT 1");
Cursor intCur = res.query(MediaStore.Audio.Media.getContentUri("phoneStorage"),
new String[] {"ARTIST"}, null, null, "RANDOM() LIMIT 1");
Cursor curCursor = null;
if (extCur != null && intCur == null) {
curCursor = extCur;
} else if (intCur != null && extCur == null) {
curCursor = intCur;
} else if (intCur != null && extCur != null) {
Random rand = new Random(System.currentTimeMillis());
int r = rand.nextInt(2);
if (r == 0) {
curCursor = intCur;
extCur.close();
} else {
curCursor = extCur;
intCur.close();
}
}
if (curCursor != null) {
if (curCursor.moveToFirst())
curArtist = curCursor.getString(0);
curCursor.close();
}
res = null;
if (curArtist == null) {
if ((mFirstImage && mRetries == ERROR_MAX_RETRIES) || !mFirstImage)
mRenderer.setError(MsRenderer.ERROR_NOARTIST);
handleGetImageError(false);
return;
}
curArtist = curArtist.replace("&", "and");
curArtist = curArtist.replace(' ', '_');
if (mNotFound.contains(curArtist)) {
if (mNotFound.size() >= MAX_NOT_FOUND)
mNotFound.clear();
handleGetImageError(true);
return;
}
HttpResponse resp = null;
try {
HttpGet hget = new HttpGet(WIKI_COMMONS_BASE + "/wiki/Category:" + curArtist);
resp = client.execute(hget);
} catch (ClientProtocolException cpe) {
handleGetImageError(false);
return;
} catch (IOException ioe) {
handleGetImageError(false);
return;
} catch (IllegalArgumentException iae) {
mNotFound.add(curArtist);
handleGetImageError(true);
return;
}
HttpEntity ent = null;
if (resp != null)
ent = resp.getEntity();
else {
handleGetImageError(false);
return;
}
if (resp.getStatusLine().equals("HTTP/1.0 404 Not Found")) {
mNotFound.add(curArtist);
handleGetImageError(true);
return;
}
if (ent == null) {
handleGetImageError(false);
return;
}
try {
xr.parse(new InputSource(ent.getContent()));
} catch (IOException ioe) {
handleGetImageError(false);
return;
} catch (SAXException se) {
handleGetImageError(false);
return;
}
if (!imgFindHand.isMusician()) {
mNotFound.add(curArtist);
handleGetImageError(true);
return;
}
thumbs = imgFindHand.getThumbs();
if (thumbs == null || thumbs.size() == 0) {
mNotFound.add(curArtist);
handleGetImageError(true);
return;
}
}
int maxIndex = 0;
if (imgFindHand.isSorted() && mSelection.equals("best") && mRenderer.getImageDisplay() != MsRenderer.CUBE_MODE) {
for (int i = 0; i < thumbs.size(); i++) {
WikiCommonsThumb thumb = thumbs.get(i);
float diff = Math.abs(canvasRatio - thumb.getRatio());
if (diff > 0 && diff <= mThresh && mSelection.equals("best")) {
maxIndex = i;
} else if (i == 0 && mSelection.equals("best") && mSkipArtist &&
diff > mThresh) {
mNotFound.add(curArtist);
handleGetImageError(true);
return;
} else if (!mSelection.equals("best")){
maxIndex = thumbs.size() - 1;
break;
}
}
} else if (mSelection.equals("best") && mRenderer.getImageDisplay() != MsRenderer.CUBE_MODE) {
maxIndex = 0;
} else {
maxIndex = thumbs.size() - 1;
}
ArrayList<WikiCommonsImage> pi = new ArrayList<WikiCommonsImage>();
for (int i = 0; i <= maxIndex; i++) {
WikiCommonsThumb thumb = thumbs.get(i);
if (thumb == null) {
return;
}
String imageLink = thumb.getPageLink();
HttpResponse resp = null;
try {
HttpGet hget = new HttpGet(imageLink);
resp = client.execute(hget);
} catch (ClientProtocolException cpe) {
continue;
} catch (IOException ioe) {
continue;
} catch (IllegalArgumentException iae) {
continue;
}
if (resp == null) {
continue;
}
HttpEntity ent = resp.getEntity();
if (ent == null) {
continue;
}
ImageFileHandler imgFileHand = new ImageFileHandler(imageLink);
try {
xr.setContentHandler(imgFileHand);
xr.setErrorHandler(imgFileHand);
xr.parse(new InputSource(ent.getContent()));
} catch (IOException ioe) {
continue;
} catch (SAXException se) {
continue;
}
WikiCommonsImage tempWikiImage = imgFileHand.getWikiCommonsImage();
if (tempWikiImage == null || tempWikiImage.getFullLink() == null ||
tempWikiImage.getThumbLink() == null) {
continue;
}
if ((tempWikiImage.getThumbWidth() >= canvasWidth - canvasWidthThresh
|| tempWikiImage.getThumbHeight() >= canvasHeight - canvasHeightThresh) && !mFull) {
pi.add(tempWikiImage);
} else if ((tempWikiImage.getFullWidth() >= canvasWidth - canvasWidthThresh ||
tempWikiImage.getFullHeight() >= canvasHeight - canvasHeightThresh) ||
(mFull && mRenderer.getImageDisplay() != MsRenderer.CUBE_MODE)) {
pi.add(tempWikiImage);
} else if (mSelection.equals("any")) {
pi.add(tempWikiImage);
}
}
if (pi.size() == 0) {
mNotFound.add(curArtist);
handleGetImageError(true);
return;
}
Random rand = new Random(System.currentTimeMillis());
int r = rand.nextInt(pi.size());
WikiCommonsImage tempWikiImage = pi.get(r);
float wr = 1.0f;
float hr = 1.0f;
String link;
if (tempWikiImage.getThumbWidth() >= canvasWidth - canvasWidthThresh
|| tempWikiImage.getThumbHeight() >= canvasHeight - canvasHeightThresh) {
wr = tempWikiImage.getThumbWidth()/canvasWidth;
hr = tempWikiImage.getThumbHeight()/canvasHeight;
link = tempWikiImage.getThumbLink();
} else {
wr = tempWikiImage.getFullWidth()/canvasWidth;
hr = tempWikiImage.getFullHeight()/canvasHeight;
link = tempWikiImage.getFullLink();
}
int ssample = (int) Math.ceil(Math.min(wr,hr));
HttpResponse resp;
try {
HttpGet hget = new HttpGet(link);
resp = client.execute(hget);
} catch (ClientProtocolException cpe) {
handleGetImageError(false);
return;
} catch (IOException ioe) {
handleGetImageError(false);
return;
} catch (IllegalArgumentException iae) {
mNotFound.add(curArtist);
handleGetImageError(true);
return;
} catch (IllegalStateException ise) {
handleGetImageError(true);
return;
}
if (resp == null) {
handleGetImageError(false);
}
HttpEntity ent = resp.getEntity();
if (ent == null) {
handleGetImageError(true);
return;
}
while (mSettingBg) {
SystemClock.sleep(100);
}
mSettingWikiImage = true;
Bitmap tempBmap = null;
System.gc();
try {
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inSampleSize = ssample;
tempBmap = BitmapFactory.decodeStream(new FlushedInputStream(ent.getContent()),
null, opt);
if (tempBmap == null) {
//Log.e("Musician Slideshow", "Bitmap is null :(");
handleGetImageError(false);
return;
}
} catch (IOException ioe) {
handleGetImageError(false);
return;
} catch (OutOfMemoryError ome) {
Log.e("Musician Slideshow", "Error allocating memory for bitmap while loading musician: " +
curArtist + " error:"+ ome.getMessage());
handleGetImageError(false);
return;
}
Background bg = scaleBmap(tempBmap, tempWikiImage);
if (bg == null) {
handleGetImageError(false);
return;
}
String[] words = curArtist.split("[_]");
if (words == null)
words = new String[] {curArtist};
tempWikiImage.setText(words);
WikiCommonsImage newWikiImage = tempWikiImage;
if (mRenderer.getImageDisplay() != MsRenderer.CUBE_MODE && curWikiImage != null)
mRenderer.setFadeOut(MsRenderer.MAX_FADEIN);
else
mRenderer.setFadeOut(MsRenderer.MAX_FADEOUT);
if (curWikiImage == null) {
mRenderer.setCurWikiImage(newWikiImage);
} else if (mRenderer.getImageDisplay() == MsRenderer.CUBE_MODE) {
mRenderer.setCurWikiImage(newWikiImage);
mRenderer.setNewWikiImage(null);
} else {
mRenderer.setNewWikiImage(newWikiImage);
}
curWikiImage = newWikiImage;
newWikiImage = null;
mSettingWikiImage = false;
if (mFirstImage) {
mFirstImage = false;
}
if (mRefreshGesture) {
mRefreshGesture = false;
mNotifyMan.cancelAll();
}
mScheduledUpdate = System.currentTimeMillis() + mRefreshRate * 60 * 1000;
if (mVisible) {
mImageViewed = true;
mImageScheduler.setNextRun(mScheduledUpdate);
} else
mImageViewed = false;
mRetries = 0;
client.getConnectionManager().shutdown();
client = null;
mRenderer.setFadeIn(MsRenderer.MAX_FADEOUT);
mGettingWikiImage = false;
}
private Background scaleBmap(Bitmap tempBmap, Background wikiImage) {
float scalew;
float scaleh;
int canvasWidth = mRenderer.getCanvasWidth();
int canvasHeight = mRenderer.getCanvasHeight();
try {
scalew = (float) canvasWidth/tempBmap.getWidth();
scaleh = (float) canvasHeight/tempBmap.getHeight();
} catch (ArithmeticException ae) {
scalew = 1.0f;
scaleh = 1.0f;
}
float scale = Math.min(scalew, scaleh);
int maxTexSize = mRenderer.getMaxTexSize();
Bitmap scaledBmap = null;
int width, height;
if (scale < 1.0) {
width = (int) (tempBmap.getWidth() * scale);
height = (int) (tempBmap.getHeight() * scale);
} else {
width = tempBmap.getWidth();
height = tempBmap.getHeight();
}
wikiImage.setScaledWidth(width);
wikiImage.setScaledHeight(height);
double lgb2 = Math.log10(2);
int heightExp = (int) Math.ceil(Math.log10(height)/lgb2);
int widthExp = (int) Math.ceil(Math.log10(width)/lgb2);
width = (int) Math.pow(2, widthExp);
height = (int) Math.pow(2, heightExp);
if (width <= 0 || width > maxTexSize) {
width = maxTexSize;
}
if (height <= 0 || height > maxTexSize) {
height = maxTexSize;
}
wikiImage.setTexWidth(width);
wikiImage.setTexHeight(height);
try {
System.gc();
scaledBmap = Bitmap.createScaledBitmap(tempBmap, width, height, true);
} catch (OutOfMemoryError ome) {
Log.e("Musician Slideshow", "Out of memory error while creating scaled bitmap" + ome.getMessage());
wikiImage = null;
tempBmap.recycle();
tempBmap = null;
return wikiImage;
}
if (tempBmap != scaledBmap) {
tempBmap.recycle();
}
tempBmap = null;
ByteBuffer buffer = null;
System.gc();
try {
buffer = ByteBuffer.allocateDirect(scaledBmap.getWidth() * scaledBmap.getHeight() * 4);
buffer.order(ByteOrder.nativeOrder());
byte[] newPixel = new byte[4];
for (int y = scaledBmap.getHeight() - 1; y > 0; y--) {
for (int x = 0; x < scaledBmap.getWidth(); x++) {
int pixel = scaledBmap.getPixel(x, y);
byte red = (byte) (pixel >> 16 & 0xFF);
byte green = (byte) (pixel >> 8 & 0xFF);
byte blue = (byte) (pixel & 0xFF);
newPixel[0] = red;
newPixel[1] = green;
newPixel[2] = blue;
newPixel[3] = (byte) 255;
buffer.put(newPixel);
}
}
scaledBmap.recycle();
scaledBmap = null;
buffer.position(0);
wikiImage.setByteBuffer(buffer);
} catch (OutOfMemoryError ome) {
Log.e("Musician Slideshow", "Out of memory error while creating pixel buffer error: " + ome.getMessage());
scaledBmap.recycle();
scaledBmap = null;
wikiImage = null;
return wikiImage;
}
wikiImage.setScales(canvasWidth, canvasHeight);
System.gc();
return wikiImage;
}
private void handleGetImageError(boolean recoverable) {
mSettingWikiImage = false;
mGettingWikiImage = false;
if (client != null) {
client.getConnectionManager().shutdown();
client = null;
}
if (mFirstImage || mRefreshGesture) {
if (mRetries < ERROR_MAX_RETRIES) {
mRetries++;
updateImageHandlerMills(200);
} else {
mRetries = 0;
if (mRenderer.getError() == MsRenderer.ERROR_NOERROR)
mRenderer.setError(MsRenderer.ERROR_MAXRETRIES);
if (mRefreshGesture) {
mRefreshGesture = false;
mNotifyMan.cancelAll();
}
updateImageHandlerMills(ERROR_STD);
}
} else if (recoverable) {
if (mRetries < ERROR_MAX_RETRIES) {
mRetries++;
updateImageHandlerMills(ERROR_RECOVER);
} else {
mRetries = 0;
if (mRenderer.getError() == MsRenderer.ERROR_NOERROR)
mRenderer.setError(MsRenderer.ERROR_GENERIC);
if (mRefreshGesture) {
mRefreshGesture = false;
mNotifyMan.cancelAll();
}
updateImageHandlerMills(ERROR_STD);
}
} else {
mRetries = 0;
if (mRenderer.getError() == MsRenderer.ERROR_NOERROR)
mRenderer.setError(MsRenderer.ERROR_GENERIC);
updateImageHandlerMills(ERROR_STD);
}
return;
}
private void updateImageHandlerDiff(int mins, int oldRate) {
long timeLeft = mScheduledUpdate - System.currentTimeMillis();
long timeSpent = (mScheduledUpdate - timeLeft) - (mScheduledUpdate - oldRate * 60 * 1000);
if (timeLeft > 0) {
if (mins * 60 * 1000 < timeSpent) {
updateImageHandlerMills(200);
} else {
updateImageHandlerMills(mins * 60 * 1000 - timeSpent);
}
} else {
updateImageHandlerMins(mins);
}
}
private void updateImageHandlerDiff() {
long diff = mScheduledUpdate - System.currentTimeMillis();
if (diff <= 0)
updateImageHandlerMills(200);
else
updateImageHandlerMills(diff);
}
private void updateImageHandlerMins(int mins) {
long mills = mins * 60 * 1000;
updateImageHandlerMills(mills);
}
private void updateImageHandlerMills(long mills) {
mScheduledUpdate = System.currentTimeMillis() + mills;
mImageScheduler.setNextRun(mScheduledUpdate);
}
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
boolean newB;
String newS;
int newI;
float newF;
if (key == null || mRenderer == null) {
return;
}
mSettingPreferences = true;
SharedPreferences settings = getSharedPreferences(SHARED_PREFS_NAME, 0);
SharedPreferences.Editor editor = settings.edit();
if (key.equals("ms_image_select")) {
newS = prefs.getString("ms_image_select", "best");
if (!newS.equals(mSelection)) {
mSelection = newS;
editor.putString("ms_image_select", mSelection);
}
} else if (key.equals("ms_refresh_rate")) {
newS = prefs.getString("ms_refresh_rate", "3");
try {
newI = Integer.parseInt(newS) * 60;
} catch (NumberFormatException nfe) {
newI = 1 * 60;
}
if (newI != mRefreshRate) {
int oldRate = mRefreshRate;
mRefreshRate = newI;
if (!isPreview())
updateImageHandlerDiff(mRefreshRate, oldRate);
editor.putString("ms_refresh_rate", newS);
}
} else if (key.equals("ms_display_artist")) {
newB = prefs.getBoolean("ms_display_artist", true);
if (newB != mRenderer.getDisplayArtistImage()) {
mRenderer.setDisplayArtistImage(newB);
editor.putBoolean("ms_display_artist", newB);
}
} else if (key.equals("ms_display_artist_visible")) {
newB = prefs.getBoolean("ms_display_artist_visible", false);
if (newB != mRenderer.getDisplayArtistVisible()) {
mRenderer.setDisplayArtistVisible(newB);
editor.putBoolean("ms_display_artist_visible", newB);
}
} else if (key.equals("ms_image_full")) {
newB = prefs.getBoolean("ms_keep_artist", false);
if (newB != mFull) {
mFull = newB;
editor.putBoolean("ms_image_full", mFull);
}
} else if (key.equals("ms_text_color")) {
newS = prefs.getString("ms_text_color", "-1");
try {
newI = Integer.parseInt(newS);
} catch (NumberFormatException nfe) {
newI = -1;
}
if (newI != mRenderer.getTextColor()) {
mRenderer.setTextColor(newI);
editor.putString("ms_text_color", newS);
}
} else if (key.equals("ms_artist_text_size")) {
newS = prefs.getString("ms_artist_text_size", "40.0");
try {
newF = Float.parseFloat(newS);
if (newF < 20 || newF > 100)
newF = 40.0f;
} catch (NumberFormatException nfe) {
newF = 40.0f;
}
if (newF != mRenderer.getTextSize()) {
mRenderer.setTextSize(newF);
editor.putString("ms_artist_text_size", newS);
}
} else if (key.equals("ms_artist_skip")) {
boolean skip = prefs.getBoolean("ms_artist_skip", true);
if (skip != mSkipArtist) {
mSkipArtist = skip;
editor.putBoolean("ms_artist_skip", mSkipArtist);
}
} else if (key.equals("ms_image_display")) {
newS = prefs.getString("ms_image_display", "cube");
int imageDisplay = mRenderer.getImageDisplay();
if ((!newS.equals("cube") && imageDisplay == MsRenderer.CUBE_MODE) || (!newS.equals("wall") &&
imageDisplay == MsRenderer.WALL_MODE) ||
(!newS.equals("zoom") && imageDisplay == MsRenderer.ZOOM_MODE)) {
if (newS.equals("cube") && !mCubeBg.equals("none") && !isPreview()) {
mRenderer.settingBackground(true);
mRenderer.setRelease(MsRenderer.RELEASE_WALL_TEX);
setBackground(false);
mRenderer.setNewBg();
mRenderer.settingBackground(false);
} else{
mBackground.setByteBuffer(null);
mRenderer.setRelease(MsRenderer.RELEASE_CUBE_TEX | MsRenderer.RELEASE_WALL_TEX);
}
setImageDisplay(newS);
editor.putString("ms_image_display", newS);
}
} else if (key.equals("ms_cube_bg")) {
newS = prefs.getString("ms_cube_bg", "heic0719a");
if (!newS.equals(mCubeBg) && !newS.equals("custom_background")) {
mCubeBg = newS;
editor.putString("ms_cube_bg", mCubeBg);
if (!mCubeBg.equals("none") &&
mRenderer.getImageDisplay() == MsRenderer.CUBE_MODE && !isPreview()) {
mRenderer.settingBackground(true);
mRenderer.setRelease(MsRenderer.RELEASE_WALL_TEX);
setBackground(false);
mRenderer.setNewBg();
mRenderer.settingBackground(false);
} else if (mCubeBg.equals("none") && !isPreview() &&
mRenderer.getImageDisplay() == MsRenderer.CUBE_MODE) {
mBackground.setByteBuffer(null);
mRenderer.setRelease(MsRenderer.RELEASE_WALL_TEX);
mRenderer.setClearColor();
}
}
} else if (key.equals("ms_cubebg_stretch")) {
newB = prefs.getBoolean("ms_cubebg_stretch", true);
if (newB != mRenderer.getStretchBg()) {
editor.putBoolean("ms_cubebg_stretch", newB);
mRenderer.setStretchBg(newB);
}
} else if (key.equals("ms_wall_stretch")) {
newB = prefs.getBoolean("ms_wall_stretch", true);
if (newB != mRenderer.getStretchWall()) {
editor.putBoolean("ms_wall_stretch", newB);
mRenderer.setStretchWall(newB);
}
} else if (key.equals("ms_custom_background_uri")) {
newS = prefs.getString("ms_custom_background_uri", "unknown");
if (!mCubeBg.equals("custom_background") || !newS.equals(mCubeCustomBg)) {
mCubeCustomBg = newS;
editor.putString("ms_cube_bg", "custom_background");
mCubeBg = "custom_background";
if (mRenderer.getImageDisplay() == MsRenderer.CUBE_MODE && !isPreview()) {
mRenderer.settingBackground(true);
mRenderer.setRelease(MsRenderer.RELEASE_WALL_TEX);
setBackground(true);
mRenderer.setNewBg();
mRenderer.settingBackground(false);
}
}
} else if (key.equals("ms_cube_color")) {
newS = prefs.getString("ms_cube_color", "0");
int color;
try {
color = Integer.parseInt(newS);
} catch (NumberFormatException nfe) {
color = 0;
}
if (color != mRenderer.getClearColor()) {
editor.putString("ms_cube_color", newS);
mRenderer.setClearColor(color);
mRenderer.setClearColor();
}
} else if (key.equals("ms_cube_scale")) {
boolean scale = prefs.getBoolean("ms_cube_scale", true);
if (scale != mRenderer.getCubeScale()) {
mRenderer.setCubeScale(scale);
editor.putBoolean("ms_cube_scale", scale);
}
}
editor.commit();
mSettingPreferences = false;
}
@Override
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
setTouchEventsEnabled(true);
}
@Override
public void onDestroy() {
super.onDestroy();
mDestroyed = true;
while (mSettingBg || mGettingWikiImage || mSettingPreferences) {
SystemClock.sleep(100);
}
mRenderer.release();
mRenderer = null;
if (mPrefs != null)
mPrefs.unregisterOnSharedPreferenceChangeListener(this);
curWikiImage = null;
mNotFound = null;
mBackground = null;
mWall = null;
mCube = null;
mNotifyMan = null;
//setTouchEventsEnabled(false);
mImageScheduler.destroy();
mImageScheduler = null;
System.gc();
}
@Override
public void onVisibilityChanged(boolean visible) {
mVisible = visible;
if (!mVisible) {
mRenderer.setSleep(true);
if (!mImageViewed && !mFirstImage)
mImageScheduler.cancelNextRun();
} else {
mRenderer.animateText();
mRenderer.setSleep(false);
if (!mImageViewed && !isPreview() && !mFirstImage) {
mImageViewed = true;
mScheduledUpdate = System.currentTimeMillis() + mRefreshRate * 60 * 1000;
mImageScheduler.setNextRun(mScheduledUpdate);
}
}
}
@Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
super.onSurfaceChanged(holder, format, width, height);
}
@Override
public void onSurfaceCreated(SurfaceHolder holder) {
super.onSurfaceCreated(holder);
}
@Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
super.onSurfaceDestroyed(holder);
}
@Override
public void onOffsetsChanged(float xOffset, float yOffset,
float xStep, float yStep, int xPixels, int yPixels) {
}
@Override
public void onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
if (mRenderer == null)
return;
if (event.getAction() == MotionEvent.ACTION_MOVE) {
long curTime = System.currentTimeMillis();
if (curTime - mLastTouch > 500) {
mNumTaps = 0;
mLastTouch = 0;
}
mLastTouch = curTime;
mNumTaps++;
int canvasWidth = mRenderer.getCanvasWidth();
int canvasHeight = mRenderer.getCanvasHeight();
float midY = canvasHeight/2;
float midX = canvasWidth/2;
float curX = event.getX();
float curY = event.getY();
if (mNumTaps == 1) {
mFirstTouchX = event.getX();
mFirstTouchY = event.getY();
}
float xThres = (float) ((float) canvasWidth * .7);
float yThres = (float) ((float) canvasHeight * .7);
if (mNumTaps > 1 && mFirstTouchX < midX && mFirstTouchY > midY && curX > midX &&
curY < midY && Math.abs(mFirstTouchX - curX) > xThres && Math.abs(mFirstTouchY - curY) > yThres
&& curWikiImage != null && curWikiImage.getInfoLink() != null) {
mNumTaps = 0;
mLastTouch = 0;
String link = null;
if (curWikiImage != null) {
link = curWikiImage.getInfoLink();
}
if (link != null) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(link));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
} else if (mNumTaps > 1 && mFirstTouchX > midX && mFirstTouchY < midY && curX < midX &&
curY > midY && Math.abs(mFirstTouchX - curX) > xThres && Math.abs(mFirstTouchY - curY) > yThres
&& !isPreview()) {
mNumTaps = 0;
mLastTouch = 0;
int icon = android.R.drawable.sym_def_app_icon;
CharSequence tickText = "Musician Slideshow: Loading Image";
Notification notification = new Notification(icon, tickText, System.currentTimeMillis());
Context context = getApplicationContext();
CharSequence cTitle = "Musician Slideshow";
CharSequence cText = "Trying to download an image";
Intent notifyIntent = new Intent();
PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notifyIntent, 0);
notification.setLatestEventInfo(context, cTitle, cText, contentIntent);
mNotifyMan.notify(GET_IMAGE, notification);
mRefreshGesture = true;
updateImageHandlerMills(500);
} else if (mNumTaps > 1 && mFirstTouchX > midX && mFirstTouchY > midY && curX < midX &&
curY < midY && Math.abs(mFirstTouchX - curX) > xThres && Math.abs(mFirstTouchY - curY) > yThres) {
mRenderer.animateText();
mNumTaps = 0;
mLastTouch = 0;
}
}
//event.recycle();
}
}
}
|