I'm just getting started with android programming, and want to see if there is a way to programmatically set the lock screen image. I've found various ways of setting the wallpaper in the API, but I can't seem to find the equivalent ways of setting the lock screen image.
I've seen various posts saying that customising the lock screen by adding widgets or bits of applications is not possible, but surely there must be a way to set the image programmatically?
Cheers,
Robin
As of API Level 24 they have added new methods (and updated the documentation) and flags to the WallpaperManager which allow you to set a Wallpaper not only to the home screen but also to the Lockscreen
To set a Wallpaper to the Lockscreen use the new flag WallpaperManager.FLAG_LOCK, and one of the methods which take int which
WallpaperManager.getInstance(this).setStream(inputStream, null, true, WallpaperManager.FLAG_LOCK);
You can also use one of the following methods
int setStream (InputStream bitmapData, Rect visibleCropHint, boolean allowBackup, int which)
int setResource (int resid, int which)
int setBitmap (Bitmap fullImage, Rect visibleCropHint, boolean allowBackup, int which)
A nice addition is that you can now also check if you are allowed to set the wallpaper via isSetWallpaperAllowed, and get the current set wallpaper via getWallpaperFile
Check out the updated documentation for the WallpaperManager.
There is no "lock screen image" in Android. There most certainly is no "lock screen image" concept that is the same between stock Android, HTC Sense, MOTOBLUR, etc. This simply is not part of the Android SDK.
The project that Mr. Rijk points to is a security violation that pretends to be a lock screen replacement.
There is a way to do it on Samsung devices. In the intent you can put an extra.
intent.putExtra("SET_LOCKSCREEN_WALLPAPER", true);
startActivity(intent);
I've only tested this on some Samsung phones and there's no guarantee that this won't break some time in the future. Use with caution.
You can use these three methods of WalpaperManager class but it will only work for nought version devices or above it:-
public int setBitmap (Bitmap fullImage,
Rect visibleCropHint,
boolean allowBackup,
int which)
public int setResource (int resid,
int which)
public int setStream (InputStream inputStreamData,
Rect visibleCropHint,
boolean allowBackup,
int which)
Parameter of these three methods:-
Bitmap/resid/inputStreamData :-this parameter accept data
visibleCropHint:-this parameter accept Rect object which is mainly used for Cropping functionality, for more information refer to Android developer reference website, you can also pass null if u don't want cropping functionality
allowBackup:-boolean: true if the OS is permitted to back up this wallpaper image for restore to a future device; false otherwise.
which:-It is one of the most important parameter which helps you to configure wallpaper for lock screen and home wallpaper. for lock screen use WalpaperManager.FLAG_LOCK and for home wallpaper use FLAG_SYSTEM
I am giving one example to make you understand how to use it:-
WalaperManager wm = WalaperManager.getInstance();
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
wm.setBitmap(bitmap,null,true,WalpaperManager.FLAG_LOCK);//For Lock screen
Toast.makeText(context.context, "done", Toast.LENGTH_SHORT).show();
}
else{
Toast.makeText(context.context, "Lock screen walpaper not supported",
Toast.LENGTH_SHORT).show();
}
} catch (e: Exception) {
Toast.makeText(context.context, e.message, Toast.LENGTH_SHORT).show();
}
for more information visit Android developer wallpaper manager reference
There is another way to do this. at first ,you need save the pic which you wanna set in lockedscreen in a folder(suppose it's called "appName").and then ,use following code to open gallery, after gallery has opened.lead user to open "appName" folder ,and choose the pic in gallery of system. in the gallery,user can set a pic as wallpaper or lockscreen paper.
// this code to open gallery.
startActivity(new Intent(Intent.ACTION_SET_WALLPAPER));
Bitmap icon = BitmapFactory.decodeResource(getViewContext().getResources(), R.drawable.wall);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
WallpaperManager wallpaperManager = WallpaperManager.getInstance(getViewContext());
try {
wallpaperManager.setBitmap(icon, null, true, WallpaperManager.FLAG_LOCK);
} catch (IOException e) {
e.printStackTrace();
}
usage for api30+
public void onWallpaperChanged(Bitmap bitmap, boolean onHomeScreen, boolean onLockScreen) {
WallpaperManager myWallpaperManager = WallpaperManager.getInstance(getApplicationContext());
try {
if(onHomeScreen) {
myWallpaperManager.setBitmap(bitmap);// For Home screen
}
if(onLockScreen) {
myWallpaperManager.setBitmap(bitmap,null,true, WallpaperManager.FLAG_LOCK);//For Lock screen
}
} catch (IOException e) {
e.printStackTrace();
}
}
Since API level 24, you can set wallpaper to your home screen, lock screen, or both:
WallpaperManager wallpaperManager = WallpaperManager.getInstance(getApplicationContext());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
// home screen
wallpaperManager.setBitmap(mBitmap, null, true, WallpaperManager.FLAG_SYSTEM);
// lock screen
wallpaperManager.setBitmap(mBitmap, null, true, WallpaperManager.FLAG_LOCK);
// home screen & lock screen
wallpaperManager.setBitmap(mBitmap, null, true, WallpaperManager.FLAG_LOCK | WallpaperManager.FLAG_SYSTEM);
} else {
wallpaperManager.setBitmap(mBitmap);
}
source
Related
I added a feature based on the Codelabs tutorial from Google (https://codelabs.developers.google.com/codelabs/sceneform-intro/index.html?index=..%2F..index#15) which allows users to take photos of AR objects that were added into the scene. The code works fine, however, I wish to hide the PlaneRenderer (the white dots that appear when ARCore detects a surface) in the photo taken by users.
In the onClickListener for the "Capture Photo" button, I tried setting PlaneRenderer to invisible before the takePhoto() is called. This hid the PlaneRenderer on screen, but not in the photo captured.
This is my onClickListener:
capturePhotoBtn.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
arFragment.getArSceneView().getPlaneRenderer().setVisible(false);
for (TransformableNode vNode : videoNodeList){
if (vNode.isSelected()){
vNode.getTransformationSystem().selectNode(null);
}
}
takePhoto();
}
});
videoNodeList contains a list of transformableNodes, and is used to keep track of the objects added by users (as users can add more than 1 object into the scene). As the objects are transformableNodes, users can tap on them to resize/rotate, which shows a small circle underneath the selected object. So, the for-loop added is to de-select all transformableNodes when taking photos, to ensure that the small circle does not appear in the photo as well.
The takePhoto() method is from the CodeLabs tutorial, and is given as follows:
private void takePhoto() {
final String filename = generateFilename();
ArSceneView view = arFragment.getArSceneView();
// Create a bitmap the size of the scene view.
final Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),
Bitmap.Config.ARGB_8888);
// Create a handler thread to offload the processing of the image.
final HandlerThread handlerThread = new HandlerThread("PixelCopier");
handlerThread.start();
// Make the request to copy.
PixelCopy.request(view, bitmap, (copyResult) -> {
if (copyResult == PixelCopy.SUCCESS) {
try {
File file = saveBitmapToDisk(bitmap, filename);
MediaScannerConnection.scanFile(this,
new String[] { file.toString() }, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
Log.i("ExternalStorage", "Scanned " + path + ":");
Log.i("ExternalStorage", "-> uri=" + uri);
}
});
} catch (IOException e) {
Toast toast = Toast.makeText(ChromaKeyVideoActivity.this, e.toString(),
Toast.LENGTH_LONG);
toast.show();
return;
}
Snackbar snackbar = Snackbar.make(findViewById(android.R.id.content),
"Photo saved", Snackbar.LENGTH_LONG);
snackbar.setAction("Open in Photos", v -> {
File photoFile = new File(filename);
Uri photoURI = FileProvider.getUriForFile(ChromaKeyVideoActivity.this,
ChromaKeyVideoActivity.this.getPackageName() + ".provider",
photoFile);
Intent intent = new Intent(Intent.ACTION_VIEW, photoURI);
intent.setDataAndType(photoURI, "image/*");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
});
snackbar.show();
} else {
Toast toast = Toast.makeText(ChromaKeyVideoActivity.this,
"Failed to copyPixels: " + copyResult, Toast.LENGTH_LONG);
toast.show();
}
handlerThread.quitSafely();
}, new Handler(handlerThread.getLooper()));
}
To give you a clearer picture, PlaneRenderer is hidden on the device screen when the "Capture Photo" button is tapped. This is what is seen immediately after the user taps on the "Capture Photo" button:
However, PlaneRenderer still appears in the photo taken. This is the resulting image that was taken:
which is not what I was looking for as I want to hide the PlaneRenderer in the photo (ie. photo taken should not have the white dots)
Users of this app add objects by selecting an object from the menu and tapping on the PlaneRenderer, so disabling the PlaneRenderer totally is not feasible. In addition, I have another video recording feature in the app that managed to successfully hide the PlaneRenderer in the recording by simply setting PlaneRenderer to invisible, so I am not sure why it doesn't work when capturing photos.
Any help will be greatly appreciated! :)
Finally figured this out after countless of hours. Sharing my solution (may not be the best solution) in case anyone faces this same issue in the future.
I discovered that due to the handlerThread used, the takePhoto() method always happens before the PlaneRenderer was set to invisible whenever the button is tapped. So, I added a short delay to ensure that the reverse happens - ie. delay takePhoto() method for a short while such that the method will always happen after the planeRenderer is invisible.
Here is the code snippet:
capturePhotoBtn.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
arFragment.getArSceneView().getPlaneRenderer().setVisible(false);
for (TransformableNode vNode : videoNodeList){
if (vNode.isSelected()){
vNode.getTransformationSystem().selectNode(null);
}
}
v.postDelayed(new Runnable() {
public void run() {
takePhoto();
}
}, 80);
}
});
This method worked for me, but I am sure there are better solutions to solve this problem. Hope this helps someone with the same problem and feel free to contribute if you know of a better solution.
I am creating a basic camera app as a small project I'm doing to get started with Android development.
When I click on the button to take a picture, there is about a 1-second delay in which the preview freezes before unfreezing again. There is no issue with crashing - just the freezing issue. Why is this happening and how can I fix it?
Below is the method where the camera is instantiated, as well as my SurfaceView class.
private void startCamera() {
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
cameraPreviewLayout = (FrameLayout) findViewById(R.id.camera_preview);
camera = checkDeviceCamera();
camera.setDisplayOrientation(90);
mImageSurfaceView = new ImageSurfaceView(MainActivity.this, camera);
cameraPreviewLayout.addView(mImageSurfaceView);
ImageButton captureButton = (ImageButton)findViewById(R.id.imageButton);
captureButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
camera.takePicture(null, null, pictureCallback);
camera.stopPreview();
camera.startPreview();
}
});
}
public class ImageSurfaceView extends SurfaceView implements
SurfaceHolder.Callback {
private Camera camera;
private SurfaceHolder surfaceHolder;
public ImageSurfaceView(Context context, Camera camera) {
super(context);
this.camera = camera;
this.surfaceHolder = getHolder();
this.surfaceHolder.addCallback(this);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
this.camera.setPreviewDisplay(holder);
this.camera.startPreview();
this.camera.setDisplayOrientation(90);
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
EDIT: There is currently nothing in the pictureCallback.
Camera.PictureCallback pictureCallback = new Camera.PictureCallback() {
}
You don't need to call stopPreview() after takePicture(). And you don't need startPreview() on the next line. You do need startPreview() inside your onPictureTaken() callback (not in onClick() as in the posted code!!) if you want live preview to restart after the picture is captured into a Jpeg stream.
To keep your UI responsive while using camera, you should do all work with the camera on a background thread. But it is not enough to call Camera.open() or Camera.close() on some background thread. You must create a Handler thread and use it for Camera.open(). The same Looper will be used for all camera callbacks, including PictureCallback.onPictureTaken(). See my detailed walkthrough about the use of HandlerThread.
As I explained elsewhere, you can achieve even better performance if you use the new camera2 API on devices that fully support this API (but better use the old API with devices that provide only LEGACY level of camera2 support).
But if you want to get maximum from the camera ISP, this kind of freeze may be inevitable (this depends on many hardware and firmware design choices, made by the manufacturer). Some clever UI tweaks may help to conceal this effect.
You’ll need to enable access to the hidden “Developer options” menu on
your Android phone. To do that, simply tap the “About phone” option in
Settings. Then tap “Build number” seven times and you’re done. Now you
can just back out to the main Settings menu and you’ll find Developer
options somewhere near the bottom of the list.
==>Now that you’re done with that part, let the real fun begins. Tap the new Developer options menu you just enabled and scroll until you
see the following three settings (note that they may be located within
an “Advanced” subsection):
Window animation scale Transition animation scale Animator animation
scale
==>Did you see them? By default, each of those three options is set to “1x” but tapping them and changing them to “.5x” will dramatically
speed up your phone. This harmless tweak forces the device to speed up
all transition animations, and the entire user experience is faster
and smoother as a result
I'm trying to make a simple button that will turn on/off the device flashlight. I don't understand why android.hardware.camera is obsolete. What do I have to do in order to make my code working on all devices and also ones with older version of Android?
This is my code:
if (IsFlashlightOn)
{
if (getPackageManager().hasSystemFeature(
PackageManager.FEATURE_CAMERA_FLASH))
{
cam = Camera.open();
Camera.Parameters p = cam.getParameters();
p.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
cam.setParameters(p);
cam.startPreview();
}
else
{
try
{
cam.stopPreview();
cam.release();
cam = null;
}
catch (Exception ex)
{
// Ignore the exception
}
}
}
There is a mistake in the logic of your code. It's not related to any specific Android version. You are checking if the device has camera flashlight and then, turns it on. In the else block you are turning the camera flashlight off in the case when a device has no camera flashlight what will never happen if your device actually has a flashlight.
I think the code should look like below. It will toggle flashlight (turn it on, when it's turned off and turn it off when it's turned on).
boolean isFlashlightOn = false;
boolean deviceHasCameraFlash = getPackageManager().hasSystemFeature(
PackageManager.FEATURE_CAMERA_FLASH);
if(deviceHasCameraFlash) {
Camera camera = Camera.open();
Camera.Parameters parameters = camera.getParameters();
if(isFlashlightOn) {
// turn the flashlight off
parameters.setFlashMode(Parameters.FLASH_MODE_OFF);
camera.setParameters(parameters);
camera.stopPreview();
isFlashlightOn = false;
} else {
// turn the flashlight on
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
camera.setParameters(parameters);
camera.startPreview();
isFlashlightOn = true;
}
}
I couldn't test this code right now, but I think it should work, you should get the general idea now and adjust it to your purposes.
To avoid warnings in the IDE and Static Code Analysis tools, you need to add #SuppressWarnings("deprecation") annotation to the deprecated code. We need to keep it in order to have backward compatibility with older Android versions.
If you want to handle Camera on both new and old Android versions, you should prepare the separate code for these versions.
According to the documentation:
We recommend using the new android.hardware.camera2 API for new
applications.
It means you should do it in the following way:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// code for lollipop devices or newer
} else {
// code for pre-lollipop devices
}
Code for toggling flashlight with the new API would look as follows:
private void toggleFlashLight(boolean isFlashlightOn) {
CameraManager camManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
String cameraId = camManager.getCameraIdList()[0]; // Usually front camera is at 0 position.
camManager.setTorchMode(cameraId, isFlashlightOn);
}
Moreover, check out these StackOverflow threads:
Android camera android.hardware.Camera deprecated
Android Turn on/off Camera Flash Programatically with Camera2
They may be helpful while dealing with your issue.
Regards
I would like to know if my live wallpaper has been set or not, this is because I have a button "set wallpaper" that I would like to enable only if my wallpaper hasn't already been set.
Thaks to all
Thanks to ImZaat's answer I found the solution, ImZaat's code is not working for me, as I would like to know if my wallpaper is running, but not from the wallpaper engine itself, from one other activity instead (it's an Activity used for setting some preferences about the wallpaper, so it's inside the same packege).
This is what I did and it's working fine (the code is inside the onCreate() method in the Activity:
WallpaperManager wpm = WallpaperManager.getInstance(this);
WallpaperInfo info = wpm.getWallpaperInfo();
if (info != null && info.getPackageName().equals(this.getPackageName())) {
Log.d(TAG, "We're already running");
} else {
Log.d(TAG, "We're not running");
}
Would you settle for just checking if your wallpaper is already set?
In your implementation of WallpaperService#onCreateEngine() you could do:
WallpaperManager wpm = (WallpaperManager) getSystemService(WALLPAPER_SERVICE);
WallpaperInfo info = wpm.getWallpaperInfo();
if (info != null && info.getComponent().equals(new ComponentName(this, getClass()))) {
Log.d(TAG, "We're already running");
// Still might be a preview, but the user is already running your LWP.
} else {
Log.d(TAG, "We're not running, this should be a preview");
// Should definitely be a preview.
}
I know, this question was asked maaany times, but I do not think there was a solution for this. I'm developing application which should be targeted for all devices with android system and backfacing camera. The problem is I can test application on only two devices and have to be sure that it works on all devices.I think only reasonable solution would be to to find a code samples for camera api that are quaranteed to work on nearly all devices. Does anybody can provide such sources ... but sources ... that really are tested on maaaaany (ALL) devices ? I've lost all hairs from my head ... and .. and I'm loosing my mind i think... It is all because I've released app (only for tests in my company) which was tested on only two devices, and which uses camera api in a way that should work, but it appears there are some phones like for example HTC desire HD or HTC Evo 3d (with 3d camera) where the app simply crashes (because of fu..ing camera) or freezes (also because of fu..ing camera). If there is someone who have sources for camera api (taking a picture without user gui interaction, periodically) which are really tested, please be so kind and if You can, post the source or redirect me to proper place.
Hmm maybe The question should sound like this: "Is it technically possible to use camera api on all devices ?"
Maybe I will describe how I'm currently using api.
1) Initialize cam:
public void initCam()
{
LoggingFacility.debug("Attempting to initialize camera",this);
LoggingFacility.debug("Preview is enabled:"+isPreview,this);
try {
if (camera==null)
{
camera = Camera.open();
camera.setPreviewDisplay(mHolder);
if (camera!=null)
{
Camera.Parameters parameters = camera.getParameters();
List<Size> sizes = parameters.getSupportedPictureSizes();
if (sizes!=null)
{
Size min = sizes.get(0);
for (Size size : sizes)
if (size.width<min.width) min = size;
{
parameters.setPictureSize(min.width, min.height);
}
}
camera.setParameters(parameters);
setDisplayOrientation(90);
}
}
startPreview(aps);
} catch (Throwable e){
if (exceptionsCallback!=null)
exceptionsCallback.onException(e);
}
}
2) Start preview:
private void startPreview(AfterPreviewStarted after)
{
try {
if (!isPreview)
{
LoggingFacility.debug("Starting preview",this);
//camera.stopPreview();
camera.startPreview();
isPreview = true;
LoggingFacility.debug("Preview is enabled:"+isPreview,this);
}
if (after!=null) after.doAfter();
}catch(Throwable e)
{
if (exceptionsCallback!=null)
exceptionsCallback.onException(e);
}
}
3) Take picture:
public void takePicture(final PictureCallback callback)
{
LoggingFacility.debug("Attempting to take a picture",this);
if (camera!=null)
{
if (isPreview)
{
try
{
LoggingFacility.debug("preview is enabled jut before taking picture",this);
//AudioManager mgr = (AudioManager)ctx.getSystemService(Context.AUDIO_SERVICE);
//mgr.setStreamMute(AudioManager.STREAM_SYSTEM, true);
LoggingFacility.debug("Taking picture... preview will be stopped...",this);
isPreview = false;
camera.takePicture(null, new PictureCallback(){
public void onPictureTaken(byte[] arg0, Camera arg1)
{
//LoggingFacility.debug("Picture has been taken - 1t callback",CameraPreview.this);
}
}, callback);
//mgr.setStreamMute(AudioManager.STREAM_SYSTEM, false);
} catch (Throwable e){
if (exceptionsCallback!=null)
exceptionsCallback.onException(e);
}
}
}
4) Release camera after done, or after surface is disposed.
public void releaseCam()
{
LoggingFacility.debug("Attempting to release camera",this);
if (camera!=null)
{
isTakingPictures = false;
camera.stopPreview();
isPreview = false;
camera.release();
camera = null;
LoggingFacility.debug("A camera connection has been released...",this);
}
}
In 3rd code snippet in callback method Im invoking startPreview again since after taking picture a preview is disabled, and some smartphones require preview to be started to make a picture. All above method are part of class extending SurfaceView and implementing SurfaceHolder.Callback and is a part of activity.
SurfaceHolder.Callback is implemented as follows:
public void surfaceCreated(SurfaceHolder holder) {
initCam();
}
public void surfaceDestroyed(SurfaceHolder holder) {
releaseCam();
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
}
Constructor of class
CameraPreview(Context context) {
super(context);
this.ctx = context;
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
I was also considering another approach - to overcome taking picture, and instead of this to register onPreviewFrame callback and for example in this callback check the flag if a picture has been requested, if so - convert image to bitmap and use it in further processing. I was trying this approach, but then stuck with another problem - even If I register empty callback, a gui responds much slower.
For everyone who like me have problems using android camera api please refer to this link . It seems the code from this sample works on majority of smartphones.
final int PICTURE_TAKEN = 1;
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(filename)));
startActivityForResult(intent, PICTURE_TAKEN);
This works for me, haven't had complaints sofar.