1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.wallpaper.livepicker;
18 
19 import android.app.ActionBar;
20 import android.app.Activity;
21 import android.app.AlertDialog;
22 import android.app.WallpaperManager;
23 import android.app.WallpaperInfo;
24 import android.app.Dialog;
25 import android.content.DialogInterface;
26 import android.graphics.Rect;
27 import android.service.wallpaper.IWallpaperConnection;
28 import android.service.wallpaper.IWallpaperService;
29 import android.service.wallpaper.IWallpaperEngine;
30 import android.service.wallpaper.WallpaperSettingsActivity;
31 import android.content.ServiceConnection;
32 import android.content.Intent;
33 import android.content.Context;
34 import android.content.ComponentName;
35 import android.os.RemoteException;
36 import android.os.IBinder;
37 import android.os.ParcelFileDescriptor;
38 import android.os.Bundle;
39 import android.service.wallpaper.WallpaperService;
40 import android.view.Menu;
41 import android.view.MenuItem;
42 import android.view.MotionEvent;
43 import android.view.View;
44 import android.view.WindowManager;
45 import android.view.ViewGroup;
46 import android.view.Window;
47 import android.view.LayoutInflater;
48 import android.util.Log;
49 import android.widget.TextView;
50 
51 import java.io.IOException;
52 
53 public class LiveWallpaperPreview extends Activity {
54     static final String EXTRA_LIVE_WALLPAPER_INFO = "android.live_wallpaper.info";
55 
56     private static final String LOG_TAG = "LiveWallpaperPreview";
57 
58     private WallpaperManager mWallpaperManager;
59     private WallpaperConnection mWallpaperConnection;
60 
61     private String mSettings;
62     private String mPackageName;
63     private Intent mWallpaperIntent;
64 
65     private View mView;
66     private Dialog mDialog;
67 
68     @Override
onCreate(Bundle savedInstanceState)69     protected void onCreate(Bundle savedInstanceState) {
70         super.onCreate(savedInstanceState);
71         init();
72     }
73 
init()74     protected void init() {
75         Bundle extras = getIntent().getExtras();
76         WallpaperInfo info = extras.getParcelable(EXTRA_LIVE_WALLPAPER_INFO);
77         if (info == null) {
78             setResult(RESULT_CANCELED);
79             finish();
80         }
81 
82         initUI(info);
83     }
84 
initUI(WallpaperInfo info)85     protected void initUI(WallpaperInfo info) {
86         mSettings = info.getSettingsActivity();
87         mPackageName = info.getPackageName();
88         mWallpaperIntent = new Intent(WallpaperService.SERVICE_INTERFACE)
89                 .setClassName(info.getPackageName(), info.getServiceName());
90 
91         final ActionBar actionBar = getActionBar();
92         actionBar.setCustomView(R.layout.live_wallpaper_preview);
93         mView = actionBar.getCustomView();
94 
95         mWallpaperManager = WallpaperManager.getInstance(this);
96         mWallpaperConnection = new WallpaperConnection(mWallpaperIntent);
97     }
98 
99     @Override
onCreateOptionsMenu(Menu menu)100     public boolean onCreateOptionsMenu(Menu menu) {
101         if (mSettings != null) {
102             getMenuInflater().inflate(R.menu.menu_preview, menu);
103         }
104         return super.onCreateOptionsMenu(menu);
105     }
106 
setLiveWallpaper(final View v)107     public void setLiveWallpaper(final View v) {
108         if (mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_LOCK) < 0) {
109             // The lock screen does not have a wallpaper, so no need to prompt; can only set both.
110             try {
111                 setLiveWallpaper(v.getRootView().getWindowToken());
112                 setResult(RESULT_OK);
113             } catch (RuntimeException e) {
114                 Log.w(LOG_TAG, "Failure setting wallpaper", e);
115             }
116             finish();
117         } else {
118             // Otherwise, prompt to either set on home or both home and lock screen.
119             new AlertDialog.Builder(this)
120                     .setTitle(R.string.set_live_wallpaper)
121                     .setItems(R.array.which_wallpaper_options, new DialogInterface.OnClickListener() {
122                         @Override
123                         public void onClick(DialogInterface dialog, int which) {
124                             try {
125                                 setLiveWallpaper(v.getRootView().getWindowToken());
126                                 if (which == 1) {
127                                     // "Home screen and lock screen"; clear the lock screen so it
128                                     // shows through to the live wallpaper on home.
129                                     mWallpaperManager.clear(WallpaperManager.FLAG_LOCK);
130                                 }
131                                 setResult(RESULT_OK);
132                             } catch (RuntimeException e) {
133                                 Log.w(LOG_TAG, "Failure setting wallpaper", e);
134                             } catch (IOException e) {
135                                 Log.w(LOG_TAG, "Failure setting wallpaper", e);
136                             }
137                             finish();
138                         }
139                     })
140                     .show();
141         }
142     }
143 
setLiveWallpaper(IBinder windowToken)144     private void setLiveWallpaper(IBinder windowToken) {
145         mWallpaperManager.setWallpaperComponent(mWallpaperIntent.getComponent());
146         mWallpaperManager.setWallpaperOffsetSteps(0.5f, 0.0f);
147         mWallpaperManager.setWallpaperOffsets(windowToken, 0.5f, 0.0f);
148     }
149 
150     @Override
onOptionsItemSelected(MenuItem item)151     public boolean onOptionsItemSelected(MenuItem item) {
152         if (item.getItemId() == R.id.configure) {
153             Intent intent = new Intent();
154             intent.setComponent(new ComponentName(mPackageName, mSettings));
155             intent.putExtra(WallpaperSettingsActivity.EXTRA_PREVIEW_MODE, true);
156             startActivity(intent);
157             return true;
158         }
159         return super.onOptionsItemSelected(item);
160     }
161 
162     @Override
onResume()163     public void onResume() {
164         super.onResume();
165         if (mWallpaperConnection != null && mWallpaperConnection.mEngine != null) {
166             try {
167                 mWallpaperConnection.mEngine.setVisibility(true);
168             } catch (RemoteException e) {
169                 // Ignore
170             }
171         }
172     }
173 
174     @Override
onPause()175     public void onPause() {
176         super.onPause();
177         if (mWallpaperConnection != null && mWallpaperConnection.mEngine != null) {
178             try {
179                 mWallpaperConnection.mEngine.setVisibility(false);
180             } catch (RemoteException e) {
181                 // Ignore
182             }
183         }
184     }
185 
186     @Override
onAttachedToWindow()187     public void onAttachedToWindow() {
188         super.onAttachedToWindow();
189 
190         showLoading();
191 
192         mView.post(new Runnable() {
193             public void run() {
194                 if (!mWallpaperConnection.connect()) {
195                     mWallpaperConnection = null;
196                 }
197             }
198         });
199     }
200 
showLoading()201     private void showLoading() {
202         LayoutInflater inflater = LayoutInflater.from(this);
203         TextView content = (TextView) inflater.inflate(R.layout.live_wallpaper_loading, null);
204 
205         mDialog = new Dialog(this, android.R.style.Theme_Black);
206 
207         Window window = mDialog.getWindow();
208         WindowManager.LayoutParams lp = window.getAttributes();
209 
210         lp.width = WindowManager.LayoutParams.MATCH_PARENT;
211         lp.height = WindowManager.LayoutParams.MATCH_PARENT;
212         window.setType(WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA);
213 
214         mDialog.setContentView(content, new ViewGroup.LayoutParams(
215                 ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT
216         ));
217         mDialog.show();
218     }
219 
220     @Override
onDetachedFromWindow()221     public void onDetachedFromWindow() {
222         super.onDetachedFromWindow();
223 
224         if (mDialog != null) mDialog.dismiss();
225 
226         if (mWallpaperConnection != null) {
227             mWallpaperConnection.disconnect();
228         }
229         mWallpaperConnection = null;
230     }
231 
232     @Override
dispatchTouchEvent(MotionEvent ev)233     public boolean dispatchTouchEvent(MotionEvent ev) {
234         if (mWallpaperConnection != null && mWallpaperConnection.mEngine != null) {
235             MotionEvent dup = MotionEvent.obtainNoHistory(ev);
236             try {
237                 mWallpaperConnection.mEngine.dispatchPointer(dup);
238             } catch (RemoteException e) {
239             }
240         }
241 
242         if (ev.getAction() == MotionEvent.ACTION_DOWN) {
243             onUserInteraction();
244         }
245         boolean handled = getWindow().superDispatchTouchEvent(ev);
246         if (!handled) {
247             handled = onTouchEvent(ev);
248         }
249 
250         if (!handled && mWallpaperConnection != null && mWallpaperConnection.mEngine != null) {
251             int action = ev.getActionMasked();
252             try {
253                 if (action == MotionEvent.ACTION_UP) {
254                     mWallpaperConnection.mEngine.dispatchWallpaperCommand(
255                             WallpaperManager.COMMAND_TAP,
256                             (int) ev.getX(), (int) ev.getY(), 0, null);
257                 } else if (action == MotionEvent.ACTION_POINTER_UP) {
258                     int pointerIndex = ev.getActionIndex();
259                     mWallpaperConnection.mEngine.dispatchWallpaperCommand(
260                             WallpaperManager.COMMAND_SECONDARY_TAP,
261                             (int) ev.getX(pointerIndex), (int) ev.getY(pointerIndex), 0, null);
262                 }
263             } catch (RemoteException e) {
264             }
265         }
266         return handled;
267     }
268 
269     class WallpaperConnection extends IWallpaperConnection.Stub implements ServiceConnection {
270         final Intent mIntent;
271         IWallpaperService mService;
272         IWallpaperEngine mEngine;
273         boolean mConnected;
274 
WallpaperConnection(Intent intent)275         WallpaperConnection(Intent intent) {
276             mIntent = intent;
277         }
278 
connect()279         public boolean connect() {
280             synchronized (this) {
281                 if (!bindService(mIntent, this, Context.BIND_AUTO_CREATE)) {
282                     return false;
283                 }
284 
285                 mConnected = true;
286                 return true;
287             }
288         }
289 
disconnect()290         public void disconnect() {
291             synchronized (this) {
292                 mConnected = false;
293                 if (mEngine != null) {
294                     try {
295                         mEngine.destroy();
296                     } catch (RemoteException e) {
297                         // Ignore
298                     }
299                     mEngine = null;
300                 }
301                 unbindService(this);
302                 mService = null;
303             }
304         }
305 
onServiceConnected(ComponentName name, IBinder service)306         public void onServiceConnected(ComponentName name, IBinder service) {
307             if (mWallpaperConnection == this) {
308                 mService = IWallpaperService.Stub.asInterface(service);
309                 try {
310                     final View view = mView;
311                     final View root = view.getRootView();
312                     mService.attach(this, view.getWindowToken(),
313                             WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY,
314                             true, root.getWidth(), root.getHeight(),
315                             new Rect(0, 0, 0, 0));
316                 } catch (RemoteException e) {
317                     Log.w(LOG_TAG, "Failed attaching wallpaper; clearing", e);
318                 }
319             }
320         }
321 
onServiceDisconnected(ComponentName name)322         public void onServiceDisconnected(ComponentName name) {
323             mService = null;
324             mEngine = null;
325             if (mWallpaperConnection == this) {
326                 Log.w(LOG_TAG, "Wallpaper service gone: " + name);
327             }
328         }
329 
attachEngine(IWallpaperEngine engine)330         public void attachEngine(IWallpaperEngine engine) {
331             synchronized (this) {
332                 if (mConnected) {
333                     mEngine = engine;
334                     try {
335                         engine.setVisibility(true);
336                     } catch (RemoteException e) {
337                         // Ignore
338                     }
339                 } else {
340                     try {
341                         engine.destroy();
342                     } catch (RemoteException e) {
343                         // Ignore
344                     }
345                 }
346             }
347         }
348 
setWallpaper(String name)349         public ParcelFileDescriptor setWallpaper(String name) {
350             return null;
351         }
352 
353         @Override
engineShown(IWallpaperEngine engine)354         public void engineShown(IWallpaperEngine engine) throws RemoteException {
355         }
356     }
357 }
358