Loading core/java/android/view/ViewRootImpl.java +14 −7 Original line number Diff line number Diff line Loading @@ -1354,6 +1354,9 @@ public final class ViewRootImpl implements ViewParent, } if (mStopped) { if (mSurfaceHolder != null) { notifySurfaceDestroyed(); } mSurface.release(); } } Loading Loading @@ -2227,13 +2230,7 @@ public final class ViewRootImpl implements ViewParent, } mIsCreating = false; } else if (hadSurface) { mSurfaceHolder.ungetCallbacks(); SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks(); if (callbacks != null) { for (SurfaceHolder.Callback c : callbacks) { c.surfaceDestroyed(mSurfaceHolder); } } notifySurfaceDestroyed(); mSurfaceHolder.mSurfaceLock.lock(); try { mSurfaceHolder.mSurface = new Surface(); Loading Loading @@ -2497,6 +2494,16 @@ public final class ViewRootImpl implements ViewParent, mIsInTraversal = false; } private void notifySurfaceDestroyed() { mSurfaceHolder.ungetCallbacks(); SurfaceHolder.Callback[] callbacks = mSurfaceHolder.getCallbacks(); if (callbacks != null) { for (SurfaceHolder.Callback c : callbacks) { c.surfaceDestroyed(mSurfaceHolder); } } } private void maybeHandleWindowMove(Rect frame) { // TODO: Well, we are checking whether the frame has changed similarly Loading packages/SystemUI/src/com/android/systemui/doze/DozeService.java +4 −3 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ public class DozeService extends DreamService private DozeMachine mDozeMachine; private DozeServicePlugin mDozePlugin; private PluginManager mPluginManager; public DozeService() { setDebug(DEBUG); Loading @@ -53,14 +54,14 @@ public class DozeService extends DreamService finish(); return; } Dependency.get(PluginManager.class).addPluginListener(this, DozeServicePlugin.class, false /* Allow multiple */); mPluginManager = Dependency.get(PluginManager.class); mPluginManager.addPluginListener(this, DozeServicePlugin.class, false /* allowMultiple */); mDozeMachine = new DozeFactory().assembleMachine(this); } @Override public void onDestroy() { Dependency.get(PluginManager.class).removePluginListener(this); mPluginManager.removePluginListener(this); super.onDestroy(); mDozeMachine = null; } Loading services/core/java/com/android/server/locksettings/SP800Derive.java 0 → 100644 +82 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.locksettings; import java.nio.ByteBuffer; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; /** * Implementation of NIST SP800-108 * "Recommendation for Key Derivation Using Pseudorandom Functions" * Hardcoded: * [PRF=HMAC_SHA256] * [CTRLOCATION=BEFORE_FIXED] * [RLEN=32_BITS] * L = 256 * L suffix: 32 bits */ class SP800Derive { private final byte[] mKeyBytes; SP800Derive(byte[] keyBytes) { mKeyBytes = keyBytes; } private Mac getMac() { try { final Mac m = Mac.getInstance("HmacSHA256"); m.init(new SecretKeySpec(mKeyBytes, m.getAlgorithm())); return m; } catch (InvalidKeyException | NoSuchAlgorithmException e) { throw new RuntimeException(e); } } private static void update32(Mac m, int v) { m.update(ByteBuffer.allocate(Integer.BYTES).putInt(v).array()); } /** * Generate output from a single, fixed input. */ public byte[] fixedInput(byte[] fixedInput) { final Mac m = getMac(); update32(m, 1); // Hardwired counter value m.update(fixedInput); return m.doFinal(); } /** * Generate output from a label and context. We add a length field at the end of the context to * disambiguate it from the length even in the presence of zero bytes. */ public byte[] withContext(byte[] label, byte[] context) { final Mac m = getMac(); // Hardwired counter value: 1 update32(m, 1); // Hardwired counter value m.update(label); m.update((byte) 0); m.update(context); update32(m, context.length * 8); // Disambiguate context update32(m, 256); // Hardwired output length return m.doFinal(); } } services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java +40 −16 Original line number Diff line number Diff line Loading @@ -26,9 +26,9 @@ import android.hardware.weaver.V1_0.WeaverConfig; import android.hardware.weaver.V1_0.WeaverReadResponse; import android.hardware.weaver.V1_0.WeaverReadStatus; import android.hardware.weaver.V1_0.WeaverStatus; import android.security.GateKeeper; import android.os.RemoteException; import android.os.UserManager; import android.security.GateKeeper; import android.service.gatekeeper.GateKeeperResponse; import android.service.gatekeeper.IGateKeeperService; import android.util.ArrayMap; Loading Loading @@ -102,7 +102,8 @@ public class SyntheticPasswordManager { private static final int INVALID_WEAVER_SLOT = -1; private static final byte SYNTHETIC_PASSWORD_VERSION_V1 = 1; private static final byte SYNTHETIC_PASSWORD_VERSION = 2; private static final byte SYNTHETIC_PASSWORD_VERSION_V2 = 2; private static final byte SYNTHETIC_PASSWORD_VERSION_V3 = 3; private static final byte SYNTHETIC_PASSWORD_PASSWORD_BASED = 0; private static final byte SYNTHETIC_PASSWORD_TOKEN_BASED = 1; Loading @@ -128,6 +129,8 @@ public class SyntheticPasswordManager { private static final byte[] PERSONALISATION_WEAVER_PASSWORD = "weaver-pwd".getBytes(); private static final byte[] PERSONALISATION_WEAVER_KEY = "weaver-key".getBytes(); private static final byte[] PERSONALISATION_WEAVER_TOKEN = "weaver-token".getBytes(); private static final byte[] PERSONALISATION_CONTEXT = "android-synthetic-password-personalization-context".getBytes(); static class AuthenticationResult { public AuthenticationToken authToken; Loading @@ -136,6 +139,7 @@ public class SyntheticPasswordManager { } static class AuthenticationToken { private final byte mVersion; /* * Here is the relationship between all three fields: * P0 and P1 are two randomly-generated blocks. P1 is stored on disk but P0 is not. Loading @@ -146,29 +150,38 @@ public class SyntheticPasswordManager { private @Nullable byte[] P1; private @NonNull String syntheticPassword; AuthenticationToken(byte version) { mVersion = version; } private byte[] derivePassword(byte[] personalization) { if (mVersion == SYNTHETIC_PASSWORD_VERSION_V3) { return (new SP800Derive(syntheticPassword.getBytes())) .withContext(personalization, PERSONALISATION_CONTEXT); } else { return SyntheticPasswordCrypto.personalisedHash(personalization, syntheticPassword.getBytes()); } } public String deriveKeyStorePassword() { return bytesToHex(SyntheticPasswordCrypto.personalisedHash( PERSONALIZATION_KEY_STORE_PASSWORD, syntheticPassword.getBytes())); return bytesToHex(derivePassword(PERSONALIZATION_KEY_STORE_PASSWORD)); } public byte[] deriveGkPassword() { return SyntheticPasswordCrypto.personalisedHash(PERSONALIZATION_SP_GK_AUTH, syntheticPassword.getBytes()); return derivePassword(PERSONALIZATION_SP_GK_AUTH); } public byte[] deriveDiskEncryptionKey() { return SyntheticPasswordCrypto.personalisedHash(PERSONALIZATION_FBE_KEY, syntheticPassword.getBytes()); return derivePassword(PERSONALIZATION_FBE_KEY); } public byte[] deriveVendorAuthSecret() { return SyntheticPasswordCrypto.personalisedHash(PERSONALIZATION_AUTHSECRET_KEY, syntheticPassword.getBytes()); return derivePassword(PERSONALIZATION_AUTHSECRET_KEY); } public byte[] derivePasswordHashFactor() { return SyntheticPasswordCrypto.personalisedHash(PERSONALIZATION_PASSWORD_HASH, syntheticPassword.getBytes()); return derivePassword(PERSONALIZATION_PASSWORD_HASH); } private void initialize(byte[] P0, byte[] P1) { Loading @@ -185,7 +198,7 @@ public class SyntheticPasswordManager { } protected static AuthenticationToken create() { AuthenticationToken result = new AuthenticationToken(); AuthenticationToken result = new AuthenticationToken(SYNTHETIC_PASSWORD_VERSION_V3); result.initialize(secureRandom(SYNTHETIC_PASSWORD_LENGTH), secureRandom(SYNTHETIC_PASSWORD_LENGTH)); return result; Loading Loading @@ -802,7 +815,16 @@ public class SyntheticPasswordManager { } byte[] content = createSPBlob(getHandleName(handle), secret, applicationId, sid); byte[] blob = new byte[content.length + 1 + 1]; blob[0] = SYNTHETIC_PASSWORD_VERSION; /* * We can upgrade from v1 to v2 because that's just a change in the way that * the SP is stored. However, we can't upgrade to v3 because that is a change * in the way that passwords are derived from the SP. */ if (authToken.mVersion == SYNTHETIC_PASSWORD_VERSION_V3) { blob[0] = SYNTHETIC_PASSWORD_VERSION_V3; } else { blob[0] = SYNTHETIC_PASSWORD_VERSION_V2; } blob[1] = type; System.arraycopy(content, 0, blob, 2, content.length); saveState(SP_BLOB_NAME, blob, handle, userId); Loading Loading @@ -940,7 +962,9 @@ public class SyntheticPasswordManager { return null; } final byte version = blob[0]; if (version != SYNTHETIC_PASSWORD_VERSION && version != SYNTHETIC_PASSWORD_VERSION_V1) { if (version != SYNTHETIC_PASSWORD_VERSION_V3 && version != SYNTHETIC_PASSWORD_VERSION_V2 && version != SYNTHETIC_PASSWORD_VERSION_V1) { throw new RuntimeException("Unknown blob version"); } if (blob[1] != type) { Loading @@ -958,7 +982,7 @@ public class SyntheticPasswordManager { Log.e(TAG, "Fail to decrypt SP for user " + userId); return null; } AuthenticationToken result = new AuthenticationToken(); AuthenticationToken result = new AuthenticationToken(version); if (type == SYNTHETIC_PASSWORD_TOKEN_BASED) { if (!loadEscrowData(result, userId)) { Log.e(TAG, "User is not escrowable: " + userId); Loading services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +22 −0 Original line number Diff line number Diff line Loading @@ -541,6 +541,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub */ private void extractColors(WallpaperData wallpaper) { String cropFile = null; boolean defaultImageWallpaper = false; int wallpaperId; synchronized (mLock) { Loading @@ -549,6 +550,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub || wallpaper.wallpaperComponent == null; if (imageWallpaper && wallpaper.cropFile != null && wallpaper.cropFile.exists()) { cropFile = wallpaper.cropFile.getAbsolutePath(); } else if (imageWallpaper && !wallpaper.cropExists() && !wallpaper.sourceExists()) { defaultImageWallpaper = true; } wallpaperId = wallpaper.wallpaperId; } Loading @@ -560,6 +563,25 @@ public class WallpaperManagerService extends IWallpaperManager.Stub colors = WallpaperColors.fromBitmap(bitmap); bitmap.recycle(); } } else if (defaultImageWallpaper) { // There is no crop and source file because this is default image wallpaper. try (final InputStream is = WallpaperManager.openDefaultWallpaper(mContext, FLAG_SYSTEM)) { if (is != null) { try { final BitmapFactory.Options options = new BitmapFactory.Options(); final Bitmap bitmap = BitmapFactory.decodeStream(is, null, options); if (bitmap != null) { colors = WallpaperColors.fromBitmap(bitmap); bitmap.recycle(); } } catch (OutOfMemoryError e) { Slog.w(TAG, "Can't decode default wallpaper stream", e); } } } catch (IOException e) { Slog.w(TAG, "Can't close default wallpaper stream", e); } } if (colors == null) { Loading Loading
core/java/android/view/ViewRootImpl.java +14 −7 Original line number Diff line number Diff line Loading @@ -1354,6 +1354,9 @@ public final class ViewRootImpl implements ViewParent, } if (mStopped) { if (mSurfaceHolder != null) { notifySurfaceDestroyed(); } mSurface.release(); } } Loading Loading @@ -2227,13 +2230,7 @@ public final class ViewRootImpl implements ViewParent, } mIsCreating = false; } else if (hadSurface) { mSurfaceHolder.ungetCallbacks(); SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks(); if (callbacks != null) { for (SurfaceHolder.Callback c : callbacks) { c.surfaceDestroyed(mSurfaceHolder); } } notifySurfaceDestroyed(); mSurfaceHolder.mSurfaceLock.lock(); try { mSurfaceHolder.mSurface = new Surface(); Loading Loading @@ -2497,6 +2494,16 @@ public final class ViewRootImpl implements ViewParent, mIsInTraversal = false; } private void notifySurfaceDestroyed() { mSurfaceHolder.ungetCallbacks(); SurfaceHolder.Callback[] callbacks = mSurfaceHolder.getCallbacks(); if (callbacks != null) { for (SurfaceHolder.Callback c : callbacks) { c.surfaceDestroyed(mSurfaceHolder); } } } private void maybeHandleWindowMove(Rect frame) { // TODO: Well, we are checking whether the frame has changed similarly Loading
packages/SystemUI/src/com/android/systemui/doze/DozeService.java +4 −3 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ public class DozeService extends DreamService private DozeMachine mDozeMachine; private DozeServicePlugin mDozePlugin; private PluginManager mPluginManager; public DozeService() { setDebug(DEBUG); Loading @@ -53,14 +54,14 @@ public class DozeService extends DreamService finish(); return; } Dependency.get(PluginManager.class).addPluginListener(this, DozeServicePlugin.class, false /* Allow multiple */); mPluginManager = Dependency.get(PluginManager.class); mPluginManager.addPluginListener(this, DozeServicePlugin.class, false /* allowMultiple */); mDozeMachine = new DozeFactory().assembleMachine(this); } @Override public void onDestroy() { Dependency.get(PluginManager.class).removePluginListener(this); mPluginManager.removePluginListener(this); super.onDestroy(); mDozeMachine = null; } Loading
services/core/java/com/android/server/locksettings/SP800Derive.java 0 → 100644 +82 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.locksettings; import java.nio.ByteBuffer; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; /** * Implementation of NIST SP800-108 * "Recommendation for Key Derivation Using Pseudorandom Functions" * Hardcoded: * [PRF=HMAC_SHA256] * [CTRLOCATION=BEFORE_FIXED] * [RLEN=32_BITS] * L = 256 * L suffix: 32 bits */ class SP800Derive { private final byte[] mKeyBytes; SP800Derive(byte[] keyBytes) { mKeyBytes = keyBytes; } private Mac getMac() { try { final Mac m = Mac.getInstance("HmacSHA256"); m.init(new SecretKeySpec(mKeyBytes, m.getAlgorithm())); return m; } catch (InvalidKeyException | NoSuchAlgorithmException e) { throw new RuntimeException(e); } } private static void update32(Mac m, int v) { m.update(ByteBuffer.allocate(Integer.BYTES).putInt(v).array()); } /** * Generate output from a single, fixed input. */ public byte[] fixedInput(byte[] fixedInput) { final Mac m = getMac(); update32(m, 1); // Hardwired counter value m.update(fixedInput); return m.doFinal(); } /** * Generate output from a label and context. We add a length field at the end of the context to * disambiguate it from the length even in the presence of zero bytes. */ public byte[] withContext(byte[] label, byte[] context) { final Mac m = getMac(); // Hardwired counter value: 1 update32(m, 1); // Hardwired counter value m.update(label); m.update((byte) 0); m.update(context); update32(m, context.length * 8); // Disambiguate context update32(m, 256); // Hardwired output length return m.doFinal(); } }
services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java +40 −16 Original line number Diff line number Diff line Loading @@ -26,9 +26,9 @@ import android.hardware.weaver.V1_0.WeaverConfig; import android.hardware.weaver.V1_0.WeaverReadResponse; import android.hardware.weaver.V1_0.WeaverReadStatus; import android.hardware.weaver.V1_0.WeaverStatus; import android.security.GateKeeper; import android.os.RemoteException; import android.os.UserManager; import android.security.GateKeeper; import android.service.gatekeeper.GateKeeperResponse; import android.service.gatekeeper.IGateKeeperService; import android.util.ArrayMap; Loading Loading @@ -102,7 +102,8 @@ public class SyntheticPasswordManager { private static final int INVALID_WEAVER_SLOT = -1; private static final byte SYNTHETIC_PASSWORD_VERSION_V1 = 1; private static final byte SYNTHETIC_PASSWORD_VERSION = 2; private static final byte SYNTHETIC_PASSWORD_VERSION_V2 = 2; private static final byte SYNTHETIC_PASSWORD_VERSION_V3 = 3; private static final byte SYNTHETIC_PASSWORD_PASSWORD_BASED = 0; private static final byte SYNTHETIC_PASSWORD_TOKEN_BASED = 1; Loading @@ -128,6 +129,8 @@ public class SyntheticPasswordManager { private static final byte[] PERSONALISATION_WEAVER_PASSWORD = "weaver-pwd".getBytes(); private static final byte[] PERSONALISATION_WEAVER_KEY = "weaver-key".getBytes(); private static final byte[] PERSONALISATION_WEAVER_TOKEN = "weaver-token".getBytes(); private static final byte[] PERSONALISATION_CONTEXT = "android-synthetic-password-personalization-context".getBytes(); static class AuthenticationResult { public AuthenticationToken authToken; Loading @@ -136,6 +139,7 @@ public class SyntheticPasswordManager { } static class AuthenticationToken { private final byte mVersion; /* * Here is the relationship between all three fields: * P0 and P1 are two randomly-generated blocks. P1 is stored on disk but P0 is not. Loading @@ -146,29 +150,38 @@ public class SyntheticPasswordManager { private @Nullable byte[] P1; private @NonNull String syntheticPassword; AuthenticationToken(byte version) { mVersion = version; } private byte[] derivePassword(byte[] personalization) { if (mVersion == SYNTHETIC_PASSWORD_VERSION_V3) { return (new SP800Derive(syntheticPassword.getBytes())) .withContext(personalization, PERSONALISATION_CONTEXT); } else { return SyntheticPasswordCrypto.personalisedHash(personalization, syntheticPassword.getBytes()); } } public String deriveKeyStorePassword() { return bytesToHex(SyntheticPasswordCrypto.personalisedHash( PERSONALIZATION_KEY_STORE_PASSWORD, syntheticPassword.getBytes())); return bytesToHex(derivePassword(PERSONALIZATION_KEY_STORE_PASSWORD)); } public byte[] deriveGkPassword() { return SyntheticPasswordCrypto.personalisedHash(PERSONALIZATION_SP_GK_AUTH, syntheticPassword.getBytes()); return derivePassword(PERSONALIZATION_SP_GK_AUTH); } public byte[] deriveDiskEncryptionKey() { return SyntheticPasswordCrypto.personalisedHash(PERSONALIZATION_FBE_KEY, syntheticPassword.getBytes()); return derivePassword(PERSONALIZATION_FBE_KEY); } public byte[] deriveVendorAuthSecret() { return SyntheticPasswordCrypto.personalisedHash(PERSONALIZATION_AUTHSECRET_KEY, syntheticPassword.getBytes()); return derivePassword(PERSONALIZATION_AUTHSECRET_KEY); } public byte[] derivePasswordHashFactor() { return SyntheticPasswordCrypto.personalisedHash(PERSONALIZATION_PASSWORD_HASH, syntheticPassword.getBytes()); return derivePassword(PERSONALIZATION_PASSWORD_HASH); } private void initialize(byte[] P0, byte[] P1) { Loading @@ -185,7 +198,7 @@ public class SyntheticPasswordManager { } protected static AuthenticationToken create() { AuthenticationToken result = new AuthenticationToken(); AuthenticationToken result = new AuthenticationToken(SYNTHETIC_PASSWORD_VERSION_V3); result.initialize(secureRandom(SYNTHETIC_PASSWORD_LENGTH), secureRandom(SYNTHETIC_PASSWORD_LENGTH)); return result; Loading Loading @@ -802,7 +815,16 @@ public class SyntheticPasswordManager { } byte[] content = createSPBlob(getHandleName(handle), secret, applicationId, sid); byte[] blob = new byte[content.length + 1 + 1]; blob[0] = SYNTHETIC_PASSWORD_VERSION; /* * We can upgrade from v1 to v2 because that's just a change in the way that * the SP is stored. However, we can't upgrade to v3 because that is a change * in the way that passwords are derived from the SP. */ if (authToken.mVersion == SYNTHETIC_PASSWORD_VERSION_V3) { blob[0] = SYNTHETIC_PASSWORD_VERSION_V3; } else { blob[0] = SYNTHETIC_PASSWORD_VERSION_V2; } blob[1] = type; System.arraycopy(content, 0, blob, 2, content.length); saveState(SP_BLOB_NAME, blob, handle, userId); Loading Loading @@ -940,7 +962,9 @@ public class SyntheticPasswordManager { return null; } final byte version = blob[0]; if (version != SYNTHETIC_PASSWORD_VERSION && version != SYNTHETIC_PASSWORD_VERSION_V1) { if (version != SYNTHETIC_PASSWORD_VERSION_V3 && version != SYNTHETIC_PASSWORD_VERSION_V2 && version != SYNTHETIC_PASSWORD_VERSION_V1) { throw new RuntimeException("Unknown blob version"); } if (blob[1] != type) { Loading @@ -958,7 +982,7 @@ public class SyntheticPasswordManager { Log.e(TAG, "Fail to decrypt SP for user " + userId); return null; } AuthenticationToken result = new AuthenticationToken(); AuthenticationToken result = new AuthenticationToken(version); if (type == SYNTHETIC_PASSWORD_TOKEN_BASED) { if (!loadEscrowData(result, userId)) { Log.e(TAG, "User is not escrowable: " + userId); Loading
services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +22 −0 Original line number Diff line number Diff line Loading @@ -541,6 +541,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub */ private void extractColors(WallpaperData wallpaper) { String cropFile = null; boolean defaultImageWallpaper = false; int wallpaperId; synchronized (mLock) { Loading @@ -549,6 +550,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub || wallpaper.wallpaperComponent == null; if (imageWallpaper && wallpaper.cropFile != null && wallpaper.cropFile.exists()) { cropFile = wallpaper.cropFile.getAbsolutePath(); } else if (imageWallpaper && !wallpaper.cropExists() && !wallpaper.sourceExists()) { defaultImageWallpaper = true; } wallpaperId = wallpaper.wallpaperId; } Loading @@ -560,6 +563,25 @@ public class WallpaperManagerService extends IWallpaperManager.Stub colors = WallpaperColors.fromBitmap(bitmap); bitmap.recycle(); } } else if (defaultImageWallpaper) { // There is no crop and source file because this is default image wallpaper. try (final InputStream is = WallpaperManager.openDefaultWallpaper(mContext, FLAG_SYSTEM)) { if (is != null) { try { final BitmapFactory.Options options = new BitmapFactory.Options(); final Bitmap bitmap = BitmapFactory.decodeStream(is, null, options); if (bitmap != null) { colors = WallpaperColors.fromBitmap(bitmap); bitmap.recycle(); } } catch (OutOfMemoryError e) { Slog.w(TAG, "Can't decode default wallpaper stream", e); } } } catch (IOException e) { Slog.w(TAG, "Can't close default wallpaper stream", e); } } if (colors == null) { Loading