I have a floating widget (that draws over all the apps) that on long click (mouse hold) will show a relative layout (remove_relativelayout) from the bottom so that the user can close the widget and the service will be destroyed.
On most Samsung phones I get this crash:
Fatal Exception: java.lang.IllegalArgumentException: View=android.widget.RelativeLayout{762db5 G.E...... ......ID 0,0-160,160 #7f09022d app:id/remove_relativelayout} not attached to window manager
at android.view.WindowManagerGlobal.findViewLocked(WindowManagerGlobal.java:569)
at android.view.WindowManagerGlobal.updateViewLayout(WindowManagerGlobal.java:463)
at android.view.WindowManagerImpl.updateViewLayout(WindowManagerImpl.java:101)
at com.xxxx.dev.floatingwidget.services.FloatingWidgetServices.lambda$widgetLongClick$0(FloatingWidgetServices.java:20)
at com.xxxxx.dev.floatingwidget.services.FloatingWidgetServices.lambda$widgetLongClick$0$FloatingWidgetServices(FloatingWidgetServices.java)
at com.xxxxxx.dev.floatingwidget.services.-$$Lambda$FloatingWidgetServices$DhV3rKQxnQ9oEEnb70PNAJKR8NQ.onAnimationUpdate(-.java:4)
at android.animation.ValueAnimator.animateValue(ValueAnimator.java:1558)
at android.animation.ValueAnimator.animateBasedOnTime(ValueAnimator.java:1349)
at android.animation.ValueAnimator.doAnimationFrame(ValueAnimator.java:1481)
at android.animation.AnimationHandler.doAnimationFrame(AnimationHandler.java:146)
at android.animation.AnimationHandler.access$100(AnimationHandler.java:37)
at android.animation.AnimationHandler$1.doFrame(AnimationHandler.java:54)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:994)
at android.view.Choreographer.doCallbacks(Choreographer.java:794)
at android.view.Choreographer.doFrame(Choreographer.java:725)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:981)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:237)
at android.app.ActivityThread.main(ActivityThread.java:7857)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1068)
Here is on start:
WindowManager.LayoutParams paramRemove = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
windowType,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH |
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
PixelFormat.TRANSLUCENT);
paramRemove.gravity = Gravity.TOP | Gravity.LEFT;
removeView.setVisibility(View.GONE);
removeImg = removeView.findViewById(R.id.remove_img);
windowManager.addView(removeView, paramRemove);
I think its coming from this function but I'm not sure:
private void widgetLongClick() {
GlobalFunctions.printLn(">>>>>>>>>>>>Into FloatingWidgetService.chathead_longclick() ");
WindowManager.LayoutParams param_remove = (WindowManager.LayoutParams) removeView.getLayoutParams();
int x_cord_remove = (szWindow.x - removeView.getWidth()) / 2;
int y_cord_remove = szWindow.y - (removeView.getHeight() + getStatusBarHeight());
param_remove.x = x_cord_remove;
param_remove.y = y_cord_remove;
ValueAnimator va = ValueAnimator.ofFloat(szWindow.y, y_cord_remove);
int mDuration = 100;
if(removeView.isAttachedToWindow()){
if(param_remove != null){
if(windowManager !=null){
va.setDuration(mDuration);
va.addUpdateListener(animation -> {
param_remove.y = Math.round((Float) animation.getAnimatedValue());
windowManager.updateViewLayout(removeView, param_remove);
});
va.start();
}
}
}
}
I would recommend you add this removable layout into your XML file and have it be View.GONE until you require it, this way you don't have to be worried about adding it programmatically and settings the correct layout parameters (this is probably what's failing in your current code).
Once you receive the longClick on the other View, you can toggle the removable layout to be View.VISIBLE and perhaps even add combine that with a quick animation to make it seem more 'friendly' to the user.
I find the solution for my problem,
the problem was that I'm closing the activity before the view is loaded,
so what I did is to wait for 1 sec before closing the activity,
using simply:
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
//close the activity after 1 sec
}
},1000);
Related
My application is crashing and I believe it is due to the SharedPreferencesManager prefManager = SharedPreferencesManager.getInstance(this); being stored globally in Contentclass. However, if I take it out of there then I cannot use prefManager within the switch statement further down.
I want to use the number of clicks from prefManager to determine my switch statement. How can I get around this?
public class Content extends AppCompatActivity {
Button selectAnotherButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_content);
final SharedPreferencesManager prefManager = SharedPreferencesManager.getInstance(this);
selectAnotherButton = findViewById(R.id.button_select_another);
selectAnotherButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
prefManager.increaseClickCount();
for (int i = 0; i <= 100; i+=2) {
ShowRewardDialog();
}
}
});
private void ShowRewardDialog() {
String message = "";
//show dialog
// set text based on an if statement you need to create
switch (SharedPreferencesManager.getInstance(this).increaseClickCount()){
case 2 :
message = "You are rewarded with a video";
break;
case 4 :
message = "You are rewarded with a the yellow smiley face in the homepage";
break;
case 6 :
message = "You are rewarded with a video";
break;
case 8 :
message = "You are rewarded with a the green smiley face in the homepage";
break;
case 10 :
message = "You are rewarded with a video";
break;
case 12 :
message = "You are rewarded with a the red smiley face in the homepage";
break;
case 14 :
message = "You are rewarded with a video";
break;
default :
message="";
}
// custom dialog
final Dialog dialog = new Dialog(context);
dialog.setContentView(R.layout.custom_dialog);
SpannableString title = new SpannableString("YOU GAINED A REWARD");
title.setSpan(new ForegroundColorSpan(context.getResources().getColor(R.color.purple))
, 0, title.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
// set the custom dialog components - text, image and button
TextView text = dialog.findViewById(R.id.dialog_text);
dialog.setTitle(title);
text.setText(message);
Button dialogButton = dialog.findViewById(R.id.dialog_button_OK);
// if button is clicked, close the custom dialog
dialogButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dialog.dismiss();
}
});
dialog.show();
}
}
Stack Trace:
06-14 21:57:39.420 15488-15488/com.mima.chilltime E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.mima.chilltime, PID: 15488
java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.mima.chilltime/com.mima.chilltime.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.Context android.content.Context.getApplicationContext()' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2989)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3260)
at android.app.ActivityThread.access$1000(ActivityThread.java:218)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1734)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:6934)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1404)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.Context android.content.Context.getApplicationContext()' on a null object reference
at android.content.ContextWrapper.getApplicationContext(ContextWrapper.java:111)
at com.mima.chilltime.SharedPreferencesManager.<init>(SharedPreferencesManager.java:19)
at com.mima.chilltime.SharedPreferencesManager.getInstance(SharedPreferencesManager.java:25)
at com.mima.chilltime.MainActivity.<init>(MainActivity.java:25)
at java.lang.reflect.Constructor.newInstance(Native Method)
at java.lang.Class.newInstance(Class.java:1690)
at android.app.Instrumentation.newActivity(Instrumentation.java:1094)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2979)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3260)
at android.app.ActivityThread.access$1000(ActivityThread.java:218)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1734)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:6934)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1404)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199)
Try using
SharedPreferencesManager.getInstance(getApplicationContext());
instead of using this
In the SharedPreferencesManager.getInstance(this); .... this refers to the particular activity (i.e. not global) (i.e. its lifecycle directly related to the current context).
On the other hand, if you clearly need a reference to the global state of your application, then you can use ApplicationContext.
From Android Documentation (my emphasis) :
public Context getApplicationContext()
Return the context of the single, global Application object of the
current process. This generally should only be used if you need a
Context whose lifecycle is separate from the current context, that is
tied to the lifetime of the process rather than the current component.
So change to:
SharedPreferencesManager prefManager = SharedPreferencesManager.getInstance(getApplicationContext());
My app is supposed to draw an overlay (blue light filter) at a certain time. Now I have a method called
private void drawOverlay()
Which under normal circumstances works perfectly fine. However, I want to use this method from a service, that runs in the background and is already running, so that I can draw the overlay at a certain time. In some cases this works, but sometimes I get a the following error.:-
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
I understand this has something to do with the UI thread, and I am supposed to use a Looper and a handler and I have read the documentation, but I cannot fully work out how I am supposed to do this.
Can someone please clarify this.
private void drawOverlay() {
log("drawing overlay");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
log("overlay >m checking permission");
wm = (WindowManager) getSystemService(WINDOW_SERVICE);
if (permissionGranted) {
log("permission granted");
LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.screen_dimmer, null);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_FULLSCREEN
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION,
PixelFormat.TRANSLUCENT);
wm = (WindowManager) getSystemService(WINDOW_SERVICE);
wm.addView(view, params);
overlayDrawn = true;
} else {
log("no permission");
}
} else {
log("overlay drawing no permission needed (<m)");
wm = (WindowManager) getSystemService(WINDOW_SERVICE);
if (permissionGranted) {
LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.screen_dimmer, null);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_FULLSCREEN
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION,
PixelFormat.TRANSLUCENT);
wm = (WindowManager) getSystemService(WINDOW_SERVICE);
wm.addView(view, params);
}
}
}
Before the service is started the app checks if it has permission to draw an overlay, that is where the permissionGranted boolean comes from, this is only needed if the SDK version is higher than M.
I am having one of these mysterious android' issues (at least from my point of view). My app manages the device's camera via the camera2 api library. In my case I have two surfaces, one of them coming from an Image Reader object. Next I define my capture session and set those surfaces as targets. As you can see in the code below, I am following the typical workflows in such cases:
// Create ImageReader Surface
int max = 2;
mReader = ImageReader.newInstance(mWidth, mHeight, ImageFormat.YV12, max);
ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener() {
#Override
public void onImageAvailable(ImageReader mReader) {
Image image = null;
image = mReader.acquireLatestImage();
if (image == null) {
return;
}
byte[] bytes = convertYUV420ToNV21(image);
nativeVideoFrame(bytes);
image.close();
}
};
if (OPENGL_SOURCE==2){
nativeVideoInit(mWidth, mHeight, 0, false);
}
mReader.setOnImageAvailableListener(readerListener, mBackgroundHandler);
// Create Texture Surface
texture = createTexture();
mSurfaceTexture = new SurfaceTexture(texture);
mSurfaceTexture.setOnFrameAvailableListener(this);
mSurfaceTexture.setDefaultBufferSize(imageDimension.getWidth(), imageDimension.getHeight());
mSurface = new Surface(mSurfaceTexture);
//Attach surfaces to CaptureRequest
List<Surface> outputSurfaces = new ArrayList<Surface>(2);
outputSurfaces.add(mReader.getSurface());
outputSurfaces.add(mSurface);
captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
captureRequestBuilder.addTarget(mSurface);
captureRequestBuilder.addTarget(mReader.getSurface());
//Define the capture request
cameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback(){
#Override
public void onConfigured(#NonNull CameraCaptureSession cameraCaptureSession) {
//The camera is already closed
if (null == cameraDevice) {
return;
}
// When the session is ready, we start displaying the preview.
cameraCaptureSessions = cameraCaptureSession;
updatePreview();
}
#Override
public void onConfigureFailed(#NonNull CameraCaptureSession cameraCaptureSession) {
Toast.makeText(MainActivity.this, "Configuration change", Toast.LENGTH_SHORT).show();
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
The thing is that I am not having any problem running this code on my tablet Samsung TAB A. However, when trying in my Nexus 5X or my friend's Samsung S6, the app crashes dramatically throwing this error:
08-23 11:28:51.772: E/AndroidRuntime(20315): FATAL EXCEPTION: main
08-23 11:28:51.772: E/AndroidRuntime(20315): Process: com.example.opengltest, PID: 20315
08-23 11:28:51.772: E/AndroidRuntime(20315): java.lang.IllegalArgumentException: Bad argument passed to camera service
08-23 11:28:51.772: E/AndroidRuntime(20315): at android.hardware.camera2.utils.CameraBinderDecorator.throwOnError(CameraBinderDecorator.java:114)
Doing some test, I found that the problem comes from the image reader surface. If I get rid off on this surface from the capture session's settings, the code runs seamlessly.
Why is this happening only on my Nexus 5x or Samsung S6 and not in my tablet? And how can I fix it?
Thanks,
JM
If you look at the whole system logcat, the camera service should have a
more detailed line that states why your output surface set is bad.
However, YV12 is not a format that's guaranteed to be supported, so it's probably just that. Some devices support it, some don't.
The only YUV format that's guaranteed to be supported by all devices is ImageFormat.YUV_420_888.
If you want to use YV12 when possible, you'll need to check the StreamConfigurationMap.getOutputFormats() list to see if it's listed before trying to use it. But you'll still need to fall back to YUV_420_888 on many devices, so it's simplest to just support that directly and nothing else.
I'm creating a screen lock app, and faced notification able to drag down in the lock screen.
I've research it and found this solution to block the notification bar by using addView code below, but I cannot remove the view after user unlocked my app. Please advice how to remove the view.
I've try to use manager.removeView(view); in public void onDestroy() { but it crashed after run this code.
This is the error message
FATAL EXCEPTION: main
Process: com.mehuljoisar.lockscreen, PID: 10256
java.lang.IllegalArgumentException: View=android.view.View{42348cc0 V.ED.... ........ 0,0-0,0} not attached to window manager
at android.view.WindowManagerGlobal.findViewLocked(WindowManagerGlobal.java:373)
at android.view.WindowManagerGlobal.removeView(WindowManagerGlobal.java:302)
at android.view.WindowManagerImpl.removeView(WindowManagerImpl.java:79)
at com.mehuljoisar.lockscreen.LockScreenActivity.disablePullNotificationTouch(LockScreenActivity.java:261)
at com.mehuljoisar.lockscreen.LockScreenActivity.access$100(LockScreenActivity.java:24)
at com.mehuljoisar.lockscreen.LockScreenActivity$2.onClick(LockScreenActivity.java:113)
at android.view.View.performClick(View.java:4469)
at android.view.View$PerformClick.run(View.java:18788)
at android.os.Handler.handleCallback(Handler.java:808)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:5347)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:835)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:651)
at dalvik.system.NativeStart.main(Native Method)
Where should I put the removeView code?
private void disablePullNotificationTouch(String gg) {
WindowManager manager = ((WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE));
WindowManager.LayoutParams localLayoutParams = new WindowManager.LayoutParams();
localLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
localLayoutParams.gravity = Gravity.TOP; //make the line top
localLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
// this is to enable the notification to recieve touch events
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
// Draws over status bar
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
localLayoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
localLayoutParams.height = (int) (25 * getResources().getDisplayMetrics().scaledDensity);
localLayoutParams.format = PixelFormat.RGBX_8888;
View view = new View(this);
if(gg == "on") {
manager.addView(view, localLayoutParams);
}else {
manager.removeView(view);
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
disablePullNotificationTouch("on");
}
#Override
public void onDestroy() {
super.onDestroy();
disablePullNotificationTouch("off");
}
You use
WindowManager manager = ((WindowManager) this.getSystemService(Context.WINDOW_SERVICE));
Not use
WindowManager manager = ((WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE));
Try it!
protected void onPause()
{
super.onPause();
// If the screen is off then the device has been locked
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
boolean isScreenOn = powerManager.isScreenOn();
//screen locked
if (!isScreenOn) {
boolean pressed = onKeyDown(26, null);
//power button pressed
if(pressed){
//remove keyguard
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
//start intent
Intent i = new Intent(this, VoiceRecognitionActivity.class);
startActivity(i);
}
}
}
the above code does is when power button is pressed, the keyguard will be dismissed and the activity onpaused will be resumed.
However, the keyguard is not dimissed when i pressed the power button, and i have to unlock manually.
When i pressed the power button, the window of my activity flashed for a second and the keyguard window is shown.
If you want to prevent phone from turning screen off (and locking the phone in result) you should use WakeLock. You can use PowerManager.newWakeLock() with FLAG_KEEP_SCREEN_ON or even
FULL_WAKE_LOCK.
This code snippet may help:
final Window win = getWindow();
win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
// Turn on the screen unless we are being launched from the AlarmAlert
// subclass.
final boolean screenOff = getIntent().getBooleanExtra(SCREEN_OFF, false);
if (!screenOff) {
try {
// API 8+
win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON);
} catch (final Throwable whocares) {
// API 7+
win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
}
}