We start with an activity that starts a service then becomes idle until the service calls the activity again. the activity goes to onPause(i believe) and isn't started back up until the its BroadcastReceiver gets its call to start. My service creates a WindowManager as a system overlay and when the user triggers it, it is supposed to call the activity and make the activity make a new view with some stuff in it. Well everything goes through without a hitch, no errors popup and all my logs suggest that the code runs through smoothly, but the new view that is supposed to be made never comes to view. Interestingly enough though, if you click the app to start it again, up pops the view i wanted earlier. so I'm curious as to why it doesn't happen when i want it to, but instead it remains invisible. I've tried setting the view to visible, tried bringToFront(), and i even tried some flags on the intent to bring the activity to the top of the stack but none of those work. relevant code is below.
im not here to hear about why you don't think my app is good for the user or that you don't think it follows androids base "design" i just want help debugging this interesting bug.
MainActivity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = new Intent(MainActivity.this, MyService.class);
startService(intent); //if i comment out these lines and add the call
initService(); //to figureOutParam below it works perfectly
sendUserHome(); //this one as well
figureOutParam("UPDATE",0); //this is the call that i use to get through to
//the method though right now neither param is important
}
public void figureOutParam(String param, int top){
if(param.equals("UPDATE")){
View myView = new View(this);
LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
myView = inflater.inflate(R.layout.activity_main, null);
myView.setBackgroundColor(Color.BLUE);
myView.bringToFront();
setContentView(myView);
}
}
MyService (only important part involving the call back to service)
#Override
public void onCreate() {
super.onCreate();
WindowManager window = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
Display d = window.getDefaultDisplay();
int width=d.getWidth();
int height=d.getHeight();
height= (int)(height*.025);
params = new WindowManager.LayoutParams(WindowManager.LayoutParams.FILL_PARENT,height,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL|
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH |
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
params.gravity=Gravity.BOTTOM;
wm = (WindowManager) getSystemService(WINDOW_SERVICE);
}
public void updateView(String params){
Intent i = new Intent(MY_INTENT);
i.putExtra("y", this.y);
i.putExtra("param", params);
sendBroadcast(i);
}
Manifest because, well because
Try to inserting the figureOutParam("UPDATE",0); after the super.onCreate(savedInstanceState);.
Related
I want to "minimize" the application, leaving it in background doing exactly the same that when the ghostbutton mode is pressed when the user clicks a button (but don't finish it) How can I do that?
So far I'm able to create a Activity. I've initialize my members and load the WebView with "https://www.youtube.com". I'm also able to create a Service that lets me minimize the Activity, but what I want is to minimize the Activity that I've my WebView loaded. Problem When the Activity paused, WebView is also paused.
What I want now.
A ghost mode -> basically minimizing this current activity with
system overlay and showing notification for media controls that can
play/resume and exit from the ghost mode.
A MainActivity that is visible to me and only becomes the sevice
and show me
Notification control after pressing ghostmode btn
What I've handled so far
Screen orientation, meaning Activity doesn't recreate the WebView. If I'm watching some video,it just pause the video on screen orientation.
What answers I want
Can I make my current Activity to become a service?
If no, can I just create a SplashActivity that opens this make MainActivity and make this Service on button click.
AndroidManifest.xml
<service android:enabled="true" android:name=".Services.GhostModeService" />
android:hardwareAccelerated="true"
<activity android:name=".MainActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:label="#string/app_name"
android:launchMode="singleInstance">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
MainActivity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG,"classmain-> onCreate");
initializeM();
settingWebview();
initializeNavigationTab();
myoutube.loadUrl(URL);
ghostModeServiceIntent=new Intent(MainActivity.this,GhostModeService.class);
}
These are my settings.
private void settingWebview() {
myoutube.setWebViewClient(new Myyoutube());
myoutube.getSettings().setLoadsImagesAutomatically(true);
myoutube.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
myoutube.getSettings().setBuiltInZoomControls(false);
myoutube.getSettings().setLoadsImagesAutomatically(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
myoutube.getSettings().setMediaPlaybackRequiresUserGesture(true);
myoutube.getSettings().setJavaScriptEnabled(true);
myoutube.getSettings().setPluginState(WebSettings.PluginState.ON);
}
GhostmodeService
private WindowManager mWindowManager;
private View mGhostmode;
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG,"classghostservice-> onCreate()");
LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
mGhostmode = inflater.inflate(R.layout.layout_ghostmode,null,false);
//setting the layout parameters
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
500,
500,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
params.x=0;
params.y=0;
params.gravity=Gravity.END | Gravity.BOTTOM;
//getting windows services and adding the floating view to it
mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
mWindowManager.addView(mGhostmode, params);
}
Method that create my notification. This notification resumes the MainActivity.
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG,"classghostservice-> onstartCommand()");
foregroundNotification(1);
return START_NOT_STICKY;
}
[SOLVED] After a week I'm able to answer this long awaited question of How to Run Youtube In background using Webview. Yes, webview requires UI to run we can't run it in background using service, even if you do find a you way, you will still get in issues.
The clever tricks are as following:
Yes, you need to add android.permission.SYSTEM_ALERT_WINDOW because you want to make a floating window that stays on top of other apps.
Let's say you have asked for permission and ready to start MainActivity, at this point forget about setContentView(R.layout.activity_main); instead you need to add your layout in WindowManager using windowManager.addView(yourLayout, yourWindowParams);
activity_main.xml
In my layout my parent layout was DrawerLayout
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer"
android:layout_width="match_parent"
android:layout_height="match_parent".....
So, I had to define my member variable as follows
private static DrawerLayout windowMain;
MainActivity
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
windowMain = (DrawerLayout) inflater.inflate(R.layout.activity_main, null);
Now the main part is by using this windowMain, you have to call
findViewById()
eg
windowMain.findViewById(R.id.btn);
windowMain.findViewById(R.id.webview);
You also need to define its WindowManager.LayoutParams. Initializing params.
WindowManager.LayoutParams=expandParams
expandParams = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON|
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
PixelFormat.TRANSLUCENT);
expandParams.gravity = Gravity.START | Gravity.TOP;
expandParams.x = 0;
expandParams.y = 0;
Finally, you need to add windowMain and its params into windowManager by
windowManager.addView(windowMain, expandParams);
Everything is done to make a window that floats around and take whole of your screen, then do what you need to do like loading URL in webview using wv.loadURL(url). This ensures that we have loaded our webview inside a window and we just need to update the params of our windowMain so that it minimize it or even completely disappear by setting w:0 and h:0 instead of MATCH_PARENT
You can have a btn_ghost that updatesthe window like:
windowManager.updateViewLayout(windowMain, ghostParams);
Lastly, when we've created this created we can call moveTaskToBack(true); this will stop out activity move it to task, becuase we don't need it. When finishing this activity that was created but stopped we must remove our windowMain .
windowManager.removeView(windowMain);
finish()
I want to detect pressing of a back button in service. I've just tried this code but it didn't show me any log. Can somebody explain me why? And what should I do to make it work?
The whole idea of doing this was was taken from this tutorial http://www.kpbird.com/2013/03/android-detect-global-touch-event.html
public class MyService extends Service implements View.OnKeyListener{
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
LinearLayout touchLayout = new LinearLayout(this);
// set layout width 30 px and height is equal to full screen
LayoutParams lp = new LayoutParams(30, LayoutParams.MATCH_PARENT);
touchLayout.setLayoutParams(lp);
touchLayout.setBackgroundColor(Color.RED);
touchLayout.setOnKeyListener(this);
WindowManager mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
// set layout parameter of window manager
WindowManager.LayoutParams mParams = new WindowManager.LayoutParams(
30, // width of layout 30 px
WindowManager.LayoutParams.MATCH_PARENT, // height is equal to full screen
WindowManager.LayoutParams.TYPE_PHONE, // Type Phone, These are non-application windows providing user interaction with the phone (in particular incoming calls).
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, // this window won't ever get key input focus
PixelFormat.TRANSLUCENT);
mParams.gravity = Gravity.LEFT | Gravity.TOP;
mWindowManager.addView(touchLayout, mParams);
}
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK){
Log.v("Point","KeyCode_Back");
return false;
}
return false;
}
}
Your Service is not a View, implementing a View.OnKeyListener does not deliver your desired functionality.
A Service is intended to be an "Activity without UI" which runs in the background of your application. You can use Binders/Broadcasts to communicate with your service but UI interaction is best left to Activity/Fragments.
Annex:
I guess you are trying to build a overlay like in the link you posted in the comment. This Tutorial is from 2013 so things have changed.
In general the Android system discourages App beheaviour like the below described method. Coding like this, goes into the category Lockscreen/Kiosk-App behaviour which is considered as malware.
If you want to accomplish a little side menu inside your app you can do this perfectly fine without using such a service. Outside your App you still have the options of using widgets, which are more user friendly than hardcoding something on the screen.
I am attempting to familiarize myself with the android Service, for the purpose of overlaying the screen and drawing to it/interacting with the user outside of the app.
I know services aren't meant to interact with the user, but I can't find another way of accomplishing this.
I have found some resources that were quite a bit of help here on Stack Overflow. Here is another project on GitHub that is an example of something similar, but done in a different way.
As of right now, just because I am learning and want to accomplish this specific useless thing, I want there to be a Toast every time the screen is touched.
From reading and looking, my understanding is I need to start an Intent of a service. I must use the service to add a ViewGroup to the WindowManager. The handling of the touches and what is drawn to the screen is handled on the ViewGroup.
Yes, I have the service and overlay permission properly placed in the AndroidManifest.xml
Here are my 3 classes
public class MainActivity extends Activity
{
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
startService(new Intent(this, MyService.class));
finish();
}
}
public class MyService extends Service
{
#Override
public IBinder onBind(Intent p1)
{
// TODO: Implement this method
return null;
}
private MyView view;
#Override
public void onCreate()
{
// TODO: Implement this method
super.onCreate();
view = new MyView(this);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.RIGHT | Gravity.TOP;
params.setTitle("Load Average");
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
wm.addView(view, params);
}
}
public class MyView extends ViewGroup
{
public MyView(Context context){
super(context);
setLayoutParams(new LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
#Override
protected void onLayout(boolean p1, int p2, int p3, int p4, int p5)
{
// TODO: Implement this method
}
#Override
public boolean onTouchEvent(MotionEvent event)
{
// TODO: Implement this method
Toast.makeText(getContext(), "Touched", Toast.LENGTH_SHORT).show();
return true;
}
}
This code compiles and runs with no errors, and while messing with it, I CAN draw things to the screen in the draw method, but the toast in onTouchEvent never appears on the screen. Why won't it show up?
Edit: Using setOnTouchListener(...): and creating the toast in there didn't work either.
Your service creation and drawing is OK, as is your toast code. Throw a breakpoint on the Toast.makeText() and see if it is even getting called. My suspicion is that it is not.
Try creating a OnTouchListener and binding it to the ViewGroup, rather than using OnTouchEvent. This has worked for me in the past.
Edit: Corrected to OnTouchListner.
I am trying to add a view(ImageButton for example) to Window using WindowManager.addView(button),
What are the layout params so that the button can be seen on "lock screen".
Thanks in advance.
You can try adding type as WindowManager.LayoutParams.TYPE_SYSTEM_ERROR in the WindowManager.LayoutParams constructor which is illustrated below :
WindowManager.LayoutParams params=new WindowManager.LayoutParams();
params.type=WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
The aforementioned lines will make the view to appear on lock screen where you can capture touch events, click events and many others; However, you can use the below-mentioned flag for the non-touchable view.
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY
Note: As per Android Developers The above-mentioned both flags are deprecated in API Level 26 and so you can use the flag TYPE_APPLICATION_OVERLAY as a substitute.
You have to make an activity with transparent background with view on the top which you want to show on the lockscreen. Now call that activity when your phone wakes up.
Note : You have to make an service which will start your activity. You have to register a broadcast receiver to that service.
public class CrackService extends Service
{
CrackView renderView;
LayoutParams params;
WindowManager wm;
#Override
public void onCreate()
{
params = new WindowManager.LayoutParams( WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.RIGHT | Gravity.TOP;
wm = (WindowManager) getSystemService(WINDOW_SERVICE);
wm.addView(renderView, params);
}
#Override
public IBinder onBind(Intent intent)
{
// TODO Auto-generated method stub
return null;
}
}
I want make an app/service that looks like (Nexus One touch buttons)
for the navigation keys (Home, menu, Back, Search)
The buttons should always stay on top and send the command to the actually app that's running.
Someone have ideas and sample codes how to do that?
Update:
I also see and test an app which shows a "cracked display" always on top
so that technique maybe should be useful to always show the buttons on top.
Those function, show the button and catch the "touch event" and send the event
to the active program should be in a service module which runs in background.
You cannot do this kind of application. First, you cannot keep an app always on top, then you cannot dispatch key events to other apps.
You could do this:
WindowManager mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
System.out.println("Accesibilty cargado correctametne");
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mTopView = (ViewGroup) inflater.inflate(R.layout.resourceshower, null);
LayoutParams mWmlp = new WindowManager.LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
mWmlp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
mWmlp.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
mWmlp.width = 100; //size of window
mWmlp.height = 50;//size of window
mWmlp.format = PixelFormat.TRANSPARENT;
mWmlp.x =50; //position of window
mWmlp.y = 50; //position of window
mWindowManager.addView(mTopView, mWmlp);
Then if you want to get button clicks inside it, in the layout you are inflating (R.layout.resourceshower) on the buttons add this: android:onClick="launch"
and create a public method with the same name like: public void launch(View v){..}
you must create this method in the service/activity you create the floating window.