I was trying to detect touch events in background service so that I can get all the touch events when user is using any apps.
What's I've done is using WindowManager to add a small view and when running the app in the background, this small view can still be on the screen. I also set the view as an onTouchListener so when user touch inside the view, I can get the touch event.
My problem is that is there any way to detect touch events outside this small view.
Here is my code.
public class GlobalTouchService extends Service implements View.OnTouchListener {
private WindowManager mWindowManager;
private WindowManager.LayoutParams mLayoutParams;
private MyView myView;
private boolean flag = true;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
mWindowManager = (WindowManager)getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
mLayoutParams = new WindowManager.LayoutParams();
mLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
mLayoutParams.format = PixelFormat.TRANSLUCENT;
mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
mLayoutParams.x = 0;
mLayoutParams.y = 0;
mLayoutParams.height = 300;
mLayoutParams.width = 300;
myView = new MyView(this);
myView.setOnTouchListener(this);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (flag) {
flag = false;
mWindowManager.addView(myView, mLayoutParams);
}
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
float x = motionEvent.getRawX();
float y = motionEvent.getRawY();
Log.d("x,y", "X" + x + " Y" + y);
return false;
}
You can't. Android explicitly does not allow you to get touch events when you aren't the foreground app for security reasons. What you're trying to do is explicitly against what the OS wants, and if you find a way Google will plug the hole as quick as you find it. The only way to do this is on a rooted device, which means it won't work over the play store (and the way to do it there is by reading touch data from the linux device layer).
Related
I am working on how to apply live wallpaper(GIF image). When I click on apply button the default gif image set as wallpaper. I'm getting all the images from firebase. So I want to set that image as wallpaper. I don't know how to pass that gif image from LiveViewActivity to GIFWallpaperService to set that .gif image as live wallpaper instead of default image. (sorry for my bad English, hope you understand)
LiveWallpaperActivity.java //main activity(where I'm getting all the images from firebase)
|
| //pass the .gif image url by intent to next activity
|
LiveViewActivity.java
|
|
| //Here I receive the image by intent and load into imageview with glide
|
| //added a button to apply live wallpaper(.gif image)
| //pass .gif image to GIFWallpaperService class service (I don't know how to do)
|
GIFWallpaperService
LiveViewActivity
Where i add a button to apply live wallpaper
here i want to pass that .gif image to GIFWallpaperService
public class LiveViewActivity extends AppCompatActivity {
ImageView imageView;
Button setLiveWallpaper;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_live_view);
imageView = findViewById(R.id.viewImage);
Glide.with(this).load(getIntent().getStringExtra("images")).into(imageView);
setLiveWallpaper.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
applyLiveWallpaper();
}
});
}
private void applyLiveWallpaper() {
Intent intent = new Intent(
WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER);
intent.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT,
new ComponentName(this, GIFWallpaperService.class));
startActivity(intent);
}
}
GIFWallpaperService
here I want to receive .gif image that I send from LiveViewActivity
to set as live wallpaper
public class GIFWallpaperService extends WallpaperService {
#Override
public WallpaperService.Engine onCreateEngine() {
try {
Movie movie = Movie.decodeStream(getResources().getAssets().open("sea_gif.gif")); //Here is the default gif image
return new GIFWallpaperEngine(movie);
} catch (IOException e) {
Log.d("GIFWallpaperService", "Could not loaded live wallpaper");
return null;
}
}
private class GIFWallpaperEngine extends WallpaperService.Engine {
private final int frameDuration = 20;
private SurfaceHolder holder;
private Movie movie;
private boolean visible;
private Handler handler;
public GIFWallpaperEngine(Movie movie) {
this.movie = movie;
handler = new Handler();
}
#Override
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
this.holder = surfaceHolder;
}
private Runnable drawGIF = new Runnable() {
#Override
public void run() {
draw();
}
};
private void draw() {
if (visible) {
Canvas canvas = holder.lockCanvas();
canvas.save();
canvas.scale(4f, 4f);
movie.draw(canvas, -100, 0);
canvas.restore();
holder.unlockCanvasAndPost(canvas);
movie.setTime((int) (System.currentTimeMillis() % movie.duration()));
handler.removeCallbacks(drawGIF);
handler.postDelayed(drawGIF, frameDuration);
}
}
#Override
public void onVisibilityChanged(boolean visible) {
//super.onVisibilityChanged(visible);
this.visible = visible;
if (visible) {
handler.post(drawGIF);
} else {
handler.removeCallbacks(drawGIF);
}
}
#Override
public void onDestroy() {
super.onDestroy();
handler.removeCallbacks(drawGIF);
}
}
}
I don't know how to send and receive .gif image from LiveViewActivity to GIFWallpaperService
Your question is a little misty to me, but If I get you right, actually you can easily get the picture in LiveWallpaperActivity through the adapter by the context and then from this activity you can pass your image to whatever activity you want by intent.
To send a data from an activity to a service, you need to override onStartCommand there you have direct access to intent:
Override
public int onStartCommand(Intent intent, int flags, int startId) {
then from LiveViewActivity you will create the intent object to start service and then you place your image name inside the intent object :
Intent serviceIntent = new Intent(YourService.class.getName())
serviceIntent.putExtra("IMAGE_KEY", "image");
context.startService(serviceIntent);
When the service is started its onStartCommand() method will be called then you can get the image:
public int onStartCommand (Intent intent, int flags, int startId) {
String image = intent.getStringExtra("IMAGE_KEY");
return START_STICKY;
}
Try using DomainEventBus which helps in passing objects, images, and in fact any data types across all the applications.
https://greenrobot.org/eventbus/
With this, you need to register the "event bus" on creation of service and it will be able to receive the image from any component of the application.
I have created a custom View that will display a circle (the idea is that the user will be able to interact with this "ball" in various ways)
From my main activity class, I want to adjust some of the "ball's" properties, in this case change its color.
My problem is that nothing happens (no errors either, the app runs but doesn't do what I want) when I try to call the various methods from my MainActivity class, but if I do it from CircleView class, it works (for example changing the color upon touch)
Here is my custom View class (CircleView.java):
public class CircleView extends View {
private int circleColor = Color.GREEN;
private Paint paint;
public CircleView(Context context) {
super(context);
init(context, null);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_SCROLL:
this.circleColor = setRandomColor();
invalidate();
break;
case MotionEvent.ACTION_DOWN:
this.circleColor = setRandomColor();
invalidate();
break;
}
return super.onTouchEvent(event);
}
public CircleView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
paint = new Paint();
paint.setAntiAlias(true);
}
public void setCircleColor(int circleColor) {
this.circleColor = circleColor;
invalidate();
}
public int setRandomColor() {
Random random = new Random();
int randomColor = Color.argb(255, random.nextInt(), random.nextInt(), random.nextInt());
return randomColor;
}
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//...
//someXvalue, someYvalue, someRadius are being set here
//...
paint.setColor(circleColor);
canvas.drawCircle(someXvalue, someYvalue, someRadius, paint);
}
}
And here is my MainActivity.java class:
public class MainActivity extends Activity implements
GestureDetector.OnGestureListener {
private GestureDetectorCompat mDetector;
CircleView circle;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDetector = new GestureDetectorCompat(this, this);
circle = new CircleView(this);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
this.mDetector.onTouchEvent(event);
return super.onTouchEvent(event);
}
#Override
public boolean onDown(MotionEvent event) {
return true;
}
#Override
public boolean onSingleTapConfirmed(MotionEvent event) {
circle.setCircleColor(circle.setRandomColor(0));
circle.invalidate();
return true;
}
}
I am new to Android development, and Java as well. I realize it could be something with the Context, which is something I have not fully understood yet. Could also be something with the TouchEvents. I am sure that someone out there can see my mistake. Any help is appreciated.
your circle view is not a part of activity's layout , it's just a object in memory which has no link to your activity screen so solutions
1.) Either set circle as Activity's view
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDetector = new GestureDetectorCompat(this, this);
circle = new CircleView(this);
setContentView(circle);
}
2.) you can create your <yourpackagename.CircleView ...attributes .../> tag in your activity_main.xml and then use findViewById to initialize it in your activity.
1)If all you want to do with gestures is on tap, just implement an onClickListener on your View instead.
2)You aren't actually using the GestureDetector anywhere. The way it works is you set an onTouchListener for the view you want to get gestures on, and send the events to the gesture detector. You aren't ever sending data for any view to the detector, so it will never do anything.
3)Not a bug just an oddness- why circle.setColor(circle.setRandomColor())? I would expect a function named setXXX to actually set XXX, rather than having to do it yourself later. Not following that convention will work, but make debugging and maintenance hard.
Edit: Also what #Pavneet_Singh said- your circle isn't in your layout anywhere, so it won't be on screen.
I have only a simple MyGestureOverlayView extends GestureOverlayView in my layout; I want that when the user swipes and the GestureOverlayView recognizes the gesture, it doesn't change color. I want that the color will change only when I call overlay.setGestureColor(int color), but in fact this method changes the color that will have the next gesture when recognized by the super class, not while the user is swiping.
So my question is: how can I change the color of the gesture while the user is performing the gesture?
public class MyGestureOverlayView extends GestureOverlayView implements
GestureOverlayView.OnGesturePerformedListener,
GestureOverlayView.OnGestureListener {
private static final String TAG = MyGestureOverlayView.class.getName();
private GiocoActivity mContext;
private boolean mRecognized;
private GestureLibrary gestures;
public MyGestureOverlayView(Context context, AttributeSet attrs) {
super(context, attrs);
if (context instanceof GiocoActivity)
mContext = (GiocoActivity) context;
gestures = GestureLibraries.fromRawResource(mContext, R.raw.gesture);
if (!gestures.load())
mContext.finish();
addOnGesturePerformedListener(this);
addOnGestureListener(this);
}
#Override
public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
ArrayList<Prediction> predictions = gestures.recognize(gesture);
Log.d(TAG, "Gesture riconosciuta!");
// Sorry for my English :)
if (predictions.size() > 0 && predictions.get(0).score > 3.0) {
overlay.setGestureColor(Color.GREEN);
// The color doesn't change here, but it will change in the next gesture
String action = predictions.get(0).name;
mRecognized = true;
Toast.makeText(mContext, action, Toast.LENGTH_SHORT).show();
}
else {
overlay.setGestureColor(Color.RED);
// The color doesn't change here, but it will change in the next gesture
mRecognized = false;
}
Log.d(TAG, "Fine riconoscimento Gesture; esito: "+ mRecognized);
}
#Override
public void onGestureStarted(GestureOverlayView overlay, MotionEvent event) {
Log.d(TAG, "Gesture iniziata!");
}
#Override
public void onGesture(GestureOverlayView overlay, MotionEvent event) {
Log.d(TAG, "Gesture in corso!");
if (mRecognized) // Always false for the first gesture
overlay.setGestureColor(Color.GREEN); // Same as before
else
overlay.setGestureColor(Color.RED); // Same as before
}
#Override
public void onGestureEnded(GestureOverlayView overlay, MotionEvent event) {
Log.d(TAG, "Gesture finita!");
}
#Override
public void onGestureCancelled(GestureOverlayView overlay, MotionEvent event) {
Log.d(TAG, "Gesture cancellata!");
}
}
Besides, the callback method onGesturePerformed is called after onGestureEnded, so the boolean mRecognized in onGesture() is always false whem I perform a gesture for the first time and when it'll be recognized from the super class it'll be displayed red in any case (both recognized or not by my onGesturePerformedListener).
Sorry if I was complicate, this is my first question, and I found only one question similar to this, but it has no answers.
Thanks for your time.
I am using a videoView to play a video.
bVideoView = (VideoView) findViewById(R.id.bVideoView);
bVideoView.setVideoPath(videoPath);
Now I have a button,
audioToggle = (Button) findViewById(R.id.audioToggle);
Then I have the Button's OnClickListener
private static int aux = 0;
private AudioManager mAudioManager;
audioToggle.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
bVideoView.start();
mAudioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
if(aux % 2 == 0){
mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 50, 0);
aux++;
} else {
mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 0, 0);
aux++;
}
}
});
Now with this OnClickListener I am perfectly able to toggle the audio to mute and unmute when it is clicked each time. However I want something like this,
On the first click the videoView should start.
When I keep pressing the button the audio must mute.
When I release the button the audio must unmute.
I have been trying a lot and failing in some or the other way. Please help.
Do you mean:
The first time I hold the button, the video should play.
While I'm holding the button the audio must be heard.
When I release the button, the audio must be muted.
When I press and hold the button again, the audio must be heard again.
Then what you therefore need is not an OnClickListener but rather an OnTouchListener
What happens under the hood is that your OnClickListener is always called after you release your finger. Using View.OnTouchListener you can dispatch events when you press (you mean touch and hold) and release.
See http://developer.android.com/reference/android/view/View.OnTouchListener.html
Here's a sample snippet:
private static int aux = 0;
private AudioManager mAudioManager;
audioToggle.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent e) {
bVideoView.start();
mAudioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
switch(e.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 50, 0);
break;
case MotionEvent.ACTION_UP:
mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 0, 0);
break;
}
return true;
}
}
Finally, I don't recommend controlling the system's volume. Use a MediaPlayer.OnPreparedListener instead, get the VideoView’s MediaPlayer and then play around with its volume.
Edit:
Here's another sample snippet:
private MediaPlayer bVideoViewMP;
bVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
// Fetch a reference
bVideoViewMP = mp;
}
});
audioToggle.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent e) {
bVideoView.start();
switch(e.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
bVideoViewMP.setVolume(0.75f, 0.75f);
break;
case MotionEvent.ACTION_UP:
bVideoViewMP.setVolume(0, 0);
break;
}
return true;
}
}
These should be placed either on your fragment's onViewCreated() or on your activity's onCreate() method before the VideoView has been fully prepared.
I have an android device, it can only run a app (like ATM screen). Now I want to implement the following feature:
If the device is not in use for over 30 minutes, I will adjust the screen brightness to the lowest. At this time, if I touch the screen, I should adjust the screen brightness to the maximum. The user can not see any Android system menu, application, etc. They only can use this app (can't close it). This app will run in this device from the power on it and power off it.
I don't how to implement this feature.
Thanks.
You can use a class that extends service and can dim the screen brightness. Use AlarmManager to check the time that the user never touches the screen. I will give you an example of using the Service class:
public class DimScreen extends Service {
public static int ID_NOTIFICATION = 2018;
private WindowManager windowManager;
private LinearLayout saverScreen;
private PopupWindow pwindo;
boolean mHasDoubleClicked = false;
long lastPressTime;
private Boolean _enable = true;
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
super.onCreate();
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
saverScreen = new LinearLayout(this);
saverScreen.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
Bitmap sample = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
saverScreen.setBackground(new BitmapDrawable(this.getResources(),
convertColorIntoBlackAndWhiteImage(sample)));
saverScreen.setClickable(false);
saverScreen.setFocusable(false);
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.FILL_PARENT,
WindowManager.LayoutParams.FILL_PARENT,
PixelFormat.TRANSLUCENT);
params.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN
|WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
|WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
|WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
|WindowManager.LayoutParams.FLAG_DIM_BEHIND;
params.dimAmount = (float) 0.6;
params.screenBrightness = (float) 0.3;
params.systemUiVisibility = View.SYSTEM_UI_FLAG_LOW_PROFILE;
windowManager.addView(saverScreen, params);
}
#Override
public void onDestroy() {
super.onDestroy();
if (saverScreen != null) windowManager.removeView(saverScreen);
}
private Bitmap convertColorIntoBlackAndWhiteImage(Bitmap orginalBitmap) {
ColorMatrix colorMatrix = new ColorMatrix();
colorMatrix.setSaturation(2);
ColorMatrixColorFilter colorMatrixFilter = new ColorMatrixColorFilter(
colorMatrix);
Bitmap blackAndWhiteBitmap = orginalBitmap.copy(
Bitmap.Config.ARGB_8888, true);
Paint paint = new Paint();
paint.setColorFilter(colorMatrixFilter);
Canvas canvas = new Canvas(blackAndWhiteBitmap);
canvas.drawBitmap(blackAndWhiteBitmap, 0, 0, paint);
return blackAndWhiteBitmap;
}
}
In your Activity class call
startService(new Intent(this,DimScreen.class));
You only have to implement the AlarmManager now. If the user never touches the screen, launch the Service class. If the user Interrupt with the app, then call stopService.
Try this
WindowManager.LayoutParams localLayoutParams = getWindow()
.getAttributes();
localLayoutParams.screenBrightness = 0.12F;
getWindow().setAttributes(localLayoutParams);