| /* |
| * Copyright (C) 2008 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.server; |
| |
| import static android.os.FileObserver.*; |
| import static android.os.ParcelFileDescriptor.*; |
| import android.app.IWallpaperService; |
| import android.app.IWallpaperServiceCallback; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.SharedPreferences; |
| import android.content.pm.PackageManager; |
| import android.os.Binder; |
| import android.os.RemoteException; |
| import android.os.FileObserver; |
| import android.os.ParcelFileDescriptor; |
| import android.os.RemoteCallbackList; |
| import android.util.Config; |
| import android.util.Log; |
| |
| import java.io.File; |
| import java.io.FileNotFoundException; |
| |
| class WallpaperService extends IWallpaperService.Stub { |
| private static final String TAG = WallpaperService.class.getSimpleName(); |
| |
| private static final File WALLPAPER_DIR = new File( |
| "/data/data/com.android.settings/files"); |
| private static final String WALLPAPER = "wallpaper"; |
| private static final File WALLPAPER_FILE = new File(WALLPAPER_DIR, WALLPAPER); |
| |
| private static final String PREFERENCES = "wallpaper-hints"; |
| |
| private static final String HINT_WIDTH = "hintWidth"; |
| private static final String HINT_HEIGHT = "hintHeight"; |
| |
| /** |
| * List of callbacks registered they should each be notified |
| * when the wallpaper is changed. |
| */ |
| private final RemoteCallbackList<IWallpaperServiceCallback> mCallbacks |
| = new RemoteCallbackList<IWallpaperServiceCallback>(); |
| |
| /** |
| * Observes the wallpaper for changes and notifies all IWallpaperServiceCallbacks |
| * that the wallpaper has changed. The CREATE is triggered when there is no |
| * wallpaper set and is created for the first time. The CLOSE_WRITE is triggered |
| * everytime the wallpaper is changed. |
| */ |
| private final FileObserver mWallpaperObserver = new FileObserver( |
| WALLPAPER_DIR.getAbsolutePath(), CREATE | CLOSE_WRITE) { |
| @Override |
| public void onEvent(int event, String path) { |
| if (path == null) { |
| return; |
| } |
| |
| File changedFile = new File(WALLPAPER_DIR, path); |
| if (WALLPAPER_FILE.equals(changedFile)) { |
| notifyCallbacks(); |
| } |
| } |
| }; |
| |
| private final Context mContext; |
| |
| private int mWidth = -1; |
| private int mHeight = -1; |
| |
| public WallpaperService(Context context) { |
| if (Config.LOGD) Log.d(TAG, "WallpaperService startup"); |
| mContext = context; |
| createFilesDir(); |
| mWallpaperObserver.startWatching(); |
| |
| SharedPreferences preferences = mContext.getSharedPreferences(PREFERENCES, |
| Context.MODE_PRIVATE); |
| mWidth = preferences.getInt(HINT_WIDTH, -1); |
| mHeight = preferences.getInt(HINT_HEIGHT, -1); |
| } |
| |
| @Override |
| protected void finalize() throws Throwable { |
| super.finalize(); |
| mWallpaperObserver.stopWatching(); |
| } |
| |
| public void clearWallpaper() { |
| File f = WALLPAPER_FILE; |
| if (f.exists()) { |
| f.delete(); |
| } |
| } |
| |
| public void setDimensionHints(int width, int height) throws RemoteException { |
| checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS); |
| |
| if (width <= 0 || height <= 0) { |
| throw new IllegalArgumentException("width and height must be > 0"); |
| } |
| |
| if (width != mWidth || height != mHeight) { |
| mWidth = width; |
| mHeight = height; |
| |
| SharedPreferences preferences = mContext.getSharedPreferences(PREFERENCES, |
| Context.MODE_PRIVATE); |
| |
| final SharedPreferences.Editor editor = preferences.edit(); |
| editor.putInt(HINT_WIDTH, width); |
| editor.putInt(HINT_HEIGHT, height); |
| editor.commit(); |
| } |
| } |
| |
| public int getWidthHint() throws RemoteException { |
| return mWidth; |
| } |
| |
| public int getHeightHint() throws RemoteException { |
| return mHeight; |
| } |
| |
| public ParcelFileDescriptor getWallpaper(IWallpaperServiceCallback cb) { |
| try { |
| mCallbacks.register(cb); |
| File f = WALLPAPER_FILE; |
| if (!f.exists()) { |
| return null; |
| } |
| return ParcelFileDescriptor.open(f, MODE_READ_ONLY); |
| } catch (FileNotFoundException e) { |
| |
| /* Shouldn't happen as we check to see if the file exists */ |
| if (Config.LOGD) Log.d(TAG, "Error getting wallpaper", e); |
| } |
| return null; |
| } |
| |
| public ParcelFileDescriptor setWallpaper() { |
| checkPermission(android.Manifest.permission.SET_WALLPAPER); |
| try { |
| return ParcelFileDescriptor.open(WALLPAPER_FILE, MODE_CREATE|MODE_READ_WRITE); |
| } catch (FileNotFoundException e) { |
| if (Config.LOGD) Log.d(TAG, "Error setting wallpaper", e); |
| } |
| return null; |
| } |
| |
| private void createFilesDir() { |
| if (!WALLPAPER_DIR.exists()) { |
| WALLPAPER_DIR.mkdirs(); |
| } |
| } |
| |
| private void notifyCallbacks() { |
| final int n = mCallbacks.beginBroadcast(); |
| for (int i = 0; i < n; i++) { |
| try { |
| mCallbacks.getBroadcastItem(i).onWallpaperChanged(); |
| } catch (RemoteException e) { |
| |
| // The RemoteCallbackList will take care of removing |
| // the dead object for us. |
| } |
| } |
| mCallbacks.finishBroadcast(); |
| final Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED); |
| mContext.sendBroadcast(intent); |
| } |
| |
| private void checkPermission(String permission) { |
| if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(permission)) { |
| throw new SecurityException("Access denied to process: " + Binder.getCallingPid() |
| + ", must have permission " + permission); |
| } |
| } |
| } |