android6.0 壁纸设置流程讲解

时间:2022-03-23 18:17:54

主要以在launcher界面长按点击wallpaper按钮来设置壁纸的流程。

当我们点击wallpaper按钮后进入WallpaperPickerActivity.java界面,分三块上为设置按钮,中为将要设置的wallpaper图片,下为所有壁纸的缩略图。

选择好壁纸后点击设置按钮

 /packages/apps/Launcher3/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java
// Action bar
        // Show the custom action bar view
        final ActionBar actionBar = getActionBar();
        actionBar.setCustomView(R.layout.actionbar_set_wallpaper);
        actionBar.getCustomView().setOnClickListener(
                new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
// Ensure that a tile is slelected and loaded.
                        if (mSelectedTile != null && mCropView.getTileSource() != null) {
                            // Prevent user from selecting any new tile.
                            mWallpaperStrip.setVisibility(View.GONE);
                            actionBar.hide();
                            WallpaperTileInfo info = (WallpaperTileInfo) mSelectedTile.getTag();
                            info.onSave(WallpaperPickerActivity.this);//接着这个方法
                        } else {
                            // no tile was selected, so we just finish the activity and go back
                            setResult(Activity.RESULT_OK);
                            finish();
 }
                    }
                });
        mSetWallpaperButton = findViewById(R.id.set_wallpaper_button);

上面这个方法调用FileWallpaperInfo中的onSave方法

<pre name="code" class="java"> /packages/apps/Launcher3/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java@FileWallpaperInfo
@Override
public void onSave(WallpaperPickerActivity a)
{ a.setWallpaper(Uri.fromFile(mFile), true);//该setWallpaper在WallpaperCropActivity.java中实现
 

 

由上转入WallpaperCropActivity.java的setWallpaper()方法。

/packages/apps/Launcher3/WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java

 
protected void setWallpaper(Uri uri, final boolean finishActivityWhenDone) {

int rotation = BitmapUtils.getRotationFromExif(getContext(), uri);

BitmapCropTask cropTask = new BitmapCropTask( getContext(), uri, null, rotation, 0, 0, true, false, null);//该task是图片处理与切割关键

final Point bounds = cropTask.getImageBounds();

Runnable onEndCrop = new Runnable() {

public void run() {

updateWallpaperDimensions(bounds.x, bounds.y);

if (finishActivityWhenDone) {

setResult(Activity.RESULT_OK);

finish();

} } };

cropTask.setCropSize(bounds.x, bounds.y);

cropTask.setOnEndRunnable(onEndCrop);

cropTask.setNoCrop(true);

cropTask.execute(); }


 

由上转入BitmapCropTask.java,具体代码就不全贴出,关键看cropBitmap()里的wallpaperManager.setStream(is);调用

/packages/apps/Launcher3/WallpaperPicker/src/com/android/gallery3d/common/BitmapCropTask.java
public boolean cropBitmap() {
boolean failure = false;
... ... ...
wallpaperManager.setStream(is);
... ... ...
}

我们看到最后通过流数据写入,将图片资源写入到wallpaper文件里面。具体实现我们转到wallpaperManager.java这个类

/frameworks/base/core/java/android/app/wallpaperManager.java
public void setStream(InputStream data) throws IOException {
if (sGlobals.mService == null) {
Log.w(TAG, "WallpaperService not running");
return;
}
try {
ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
mContext.getOpPackageName());//这个service调用是关键,获取wallpaper文件载体
if (fd == null) {
return;
}
FileOutputStream fos = null;
try {
fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
setWallpaper(data, fos);//获取到wallpaper文件载体后往里面写如数据
} finally {
                if (fos != null) {
                    fos.close();
                }
            }
        } catch (RemoteException e) {
            // Ignore
        }
    }

private void setWallpaper(InputStream data, FileOutputStream fos)//往wallpaper文件载体里面写数据
            throws IOException {
        byte[] buffer = new byte[32768];
        int amt;
        while ((amt=data.read(buffer)) > 0) {
            fos.write(buffer, 0, amt);
        }
    }

我们看到上面有一个ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,mContext.getOpPackageName());,该setWallpaper实现在WallpaperManagerService.java中实现,由于是远程service调用所以这里用到aidl.具体接口声明在

frameworks/base/core/java/android/app/IWallpaperManagerCallback.aidl,这里不列出。


public ParcelFileDescriptor setWallpaper(String name, String callingPackage) {

checkPermission(android.Manifest.permission.SET_WALLPAPER);
if (!isWallpaperSupported(callingPackage)) {
return null;
}
synchronized (mLock) {
if (DEBUG) Slog.v(TAG, "setWallpaper");
// /M: To support Smart Book @ {
if (isSmartBookSupport()) {
mHaveUsedSmartBook = false;
}
// /@ }
int userId = UserHandle.getCallingUserId();
WallpaperData wallpaper = getWallpaperSafeLocked(userId);
final long ident = Binder.clearCallingIdentity();
try {
ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name, wallpaper);
if (pfd != null) {
wallpaper.imageWallpaperPending = true;
}
return pfd;
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }
    }

    ParcelFileDescriptor updateWallpaperBitmapLocked(String name, WallpaperData wallpaper) {
        if (name == null) name = "";
        try {
            File dir = getWallpaperDir(wallpaper.userId);
            if (!dir.exists()) {
                dir.mkdir();
                FileUtils.setPermissions(
                        dir.getPath(),
                        FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
                        -1, -1);
            }
File file = new File(dir, mWallpaperFileName);
            ParcelFileDescriptor fd = ParcelFileDescriptor.open(file,
                    MODE_CREATE|MODE_READ_WRITE|MODE_TRUNCATE);
            if (!SELinux.restorecon(file)) {
                return null;
            }
            wallpaper.name = name;
            return fd;
        } catch (FileNotFoundException e) {
            Slog.w(TAG, "Error setting wallpaper", e);
        }
        return null;
    }
private static File getWallpaperDir(int userId) {
        return Environment.getUserSystemDirectory(userId);
    }