Thursday, August 29, 2013

Adding preferences to your wallpaper

This blog will detail how to add a preferences to your wallpaper. We are going to modify the FallingRosePetals wallpaper that was created in a previous blog. It may help if you look over that tutorial first.

The full source code is available at github https://github.com/RealWorldApplications/LiveWallpaperPrefs

A quick overview of the steps we will take to modify the live wallpaper.
1. Create a file wallpaper.xml.
2. Create a file prefs.xml.
3. Modify the strings.xml file.
4. Modify the Android manifest.
5. Create a new class LiveWallpaperPreferences.java
6. Create a new class LiveWallpaperSettings.java
7. Modify the class LiveWallpaperServices.java to utilize the user changes.

This demonstration allows the user to change the background color. From this sample you should be able to implement any preferences to customize your app. First off I have to give credit to the book "Andengine Game Programming", by Jayme Schroeder and Brian Broyles. I highly recommend reading the book if you wand to create live wallpapers and games using andengine.

First create a file wallpaper.xml in the folder xml under the folder res. If necessary create the xml folder.
Add this code to the file:
<?xml version="1.0" encoding="UTF-8"?>
<wallpaper
        xmlns:android="http://schemas.android.com/apk/res/android"  
        android:thumbnail="@drawable/logo"
        android:description="@string/wallpaper_description"
        android:settingsActivity="com.ceecee.android.live.LiveWallpaperSettings"
        />
We also need to create a layout view for the available choices in background settings. Create a file prefs.xml in the layout folder. We will create a radio group with radio buttons offering the available choices in background colors.
Add this code to the newly created file:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="top"
    android:orientation="vertical" >

   <TextView 
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:textAppearance="?android:attr/textAppearanceMedium"
      
       android:text="@string/radio_background"/>
   
        <RadioGroup 
            android:id="@+id/radioBackground"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" >

            <RadioButton
                android:id="@+id/radioBlack"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/radio_black" />

          <RadioButton
             android:id="@+id/radioGreen"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="@string/radio_green"
             />
          <RadioButton
             android:id="@+id/radioBlue"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="@string/radio_blue"
             />
         </RadioGroup>
         
 

</LinearLayout>

We will need to edit the strings.xml file for the values used by our radio buttons.
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">Falling Rose Petals With Prefs</string>
    <string name="wallpaper_description">Rose Petals fall from top of screen</string>
    <string name="live_wallpaper_settings">Wallpaper Settings</string>
    <string name="radio_background">Background Color</string>
    <string name="radio_black">Black</string>
    <string name="radio_green">Green</string>
    <string name="radio_blue">Blue</string>
</resources>
Next edit the manifest so that is uses the settings file.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.ceecee.android.live"
    android:versionCode="1"
    android:versionName="1.0" >

     <uses-sdk  android:minSdkVersion="8"
        android:targetSdkVersion="17" />
    <uses-feature  
        android:glEsVersion="0x00020000"
        android:required="true"
        android:name="android.software.live_wallpaper">
    </uses-feature>

    <application
        android:icon="@drawable/logo"
        android:label="@string/app_name" >
        <!--  Live Wallpaper Service -->
        <service android:name="com.ceecee.android.live.LiveWallpaperService"
            android:enabled="true"
            android:permission="android.permission.BIND_WALLPAPER" 
            android:icon="@drawable/logo" 
            android:description="@string/wallpaper_description">
            <intent-filter android:priority="1">
                <action android:name="android.service.wallpaper.WallpaperService"/>
            </intent-filter>
            <meta-data android:name="android.service.wallpaper" 
                android:resource="@xml/wallpaper"/>
        </service>
         <activity
            android:name=".LiveWallpaperSettings"
            android:exported="true"
            android:icon="@drawable/logo"
            android:label="@string/live_wallpaper_settings"
            android:theme="@android:style/Theme.Black" >
        </activity>
    </application>

</manifest>
Now we are going to create a class for the available selections. Create a file LiveWallpaperPreferences.java
Add this code:
package com.ceecee.android.live;


import android.content.Context;
import android.content.SharedPreferences;


public class LiveWallpaperPreferences {

 // Handle for the LiveWallpaperPreferences singleton instance
 private static LiveWallpaperPreferences INSTANCE;
 
 // String containing the live wallpaper's preferences name
 private static final String PREFERENCE_NAME = "LWP_PREFS";
 
 // String containing the key to the background preference value
 private static final String BACKGROUND_KEY = "BACKGROUND_COLOR";
 private static final String DEFAULT_BACKGROUND = "Black";
 
 // Shared preference objects
 private SharedPreferences mSharedPreferences;
 private SharedPreferences.Editor mSharedPreferencesEditor;
 
 // Shared preference values
 private String mBackground;
 
 LiveWallpaperPreferences(){
  // Do nothing...
 }
 
 // Obtain the LiveWallpaperPreferences instance
 public static LiveWallpaperPreferences getInstance(){
  if(INSTANCE == null){
   INSTANCE = new LiveWallpaperPreferences();
  }
  return INSTANCE;
 }
 
 // Initialize the wallpaper's preference file
 public void initPreferences(Context pContext){
  if(mSharedPreferences == null){
   mSharedPreferences = pContext.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE);
   mSharedPreferencesEditor = mSharedPreferences.edit();
   
   mBackground = mSharedPreferences.getString(BACKGROUND_KEY, DEFAULT_BACKGROUND);
  }
 }
 
 // Return the saved value for the mBackground variable
 
 public String getBackground(){
  return mBackground;
 }
 
 public void setBackground(String pBackground){
  this.mBackground = pBackground;
  this.mSharedPreferencesEditor.putString(BACKGROUND_KEY, mBackground);
  this.mSharedPreferencesEditor.commit();
 }
}
We also need to create the file LiveWallpaperSettings.java. This activity responds to the user changes in the radio buttons.
package com.ceecee.android.live;

import android.app.Activity;
import android.os.Bundle;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.RadioGroup.OnCheckedChangeListener;

 public class LiveWallpaperSettings extends Activity implements OnCheckedChangeListener{
 
  private RadioGroup radioBackgroundGroup;
  private RadioButton radioBackgroundButton;
  private String mBackground;

  
  @Override
  protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   this.setContentView(R.layout.prefs);   
   radioBackgroundGroup = (RadioGroup) findViewById(R.id.radioBackground); 
   radioBackgroundGroup.setOnCheckedChangeListener(this); 
   
    }

  @Override
  protected void onPause() {
   // onPause(), we save the current value to the preference file.
   LiveWallpaperPreferences.getInstance().setBackground(mBackground);

   super.onPause();
  }

  @Override
  public void onCheckedChanged(RadioGroup group, int selectedId) {
   // TODO Auto-generated method stub

  selectedId = radioBackgroundGroup.getCheckedRadioButtonId();
  radioBackgroundButton = (RadioButton) findViewById(selectedId);
  mBackground = (String) radioBackgroundButton.getText();
 
  }

 }
  
Finally we need to edit the LiveWallpaperService.java file as follows. Add the variable
private String mBackground;
Now add the following code to set the background to the proper color.
@Override
 public void onCreateScene(OnCreateSceneCallback createSceneCallback) throws Exception {  
  mScene= new Scene();

//add the background to the scene 
//background color is added based on user selected radio button
  mBackground = LiveWallpaperPreferences.getInstance().getBackground();
  if(mBackground.equals("Black"))
   mScene.setBackground(new Background(0.0f, 0.0f, 0.0f)); 
  else if(mBackground.equals("Green"))
   mScene.setBackground(new Background(0.0f, 0.9f, 0.0f));
  else if(mBackground.equals("Blue")) 
   mScene.setBackground(new Background(0.0f, 0.0f, 0.9f));
Also we will need to alter the code that is executed onResumeGame
/ enable sensors when resumed
 @Override
    public void onResumeGame() {
  mBackground = LiveWallpaperPreferences.getInstance().getBackground();
  if(mBackground.equals("Black"))
   mScene.setBackground(new Background(0.0f, 0.0f, 0.0f)); 
  else if(mBackground.equals("Green"))
   mScene.setBackground(new Background(0.0f, 0.9f, 0.0f));
  else if(mBackground.equals("Blue")) 
   mScene.setBackground(new Background(0.0f, 0.0f, 0.9f));
   
         super.onResumeGame();
         this.enableAccelerationSensor(this);
    }