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()
Related
This is a very old problem, but after making so much effort, I still cannot figure out a possible solution.
The Aim
Actually quite simple. I would like to develop some full screen apps (e.g. games), where the status bar does not expand, however the user touches the screen.
The app should be able to work on Android 5.0, sdk 21 (Lollipop).
What I have done so far
I find this post, which describes how to cover the status bar with a CustomView that absorbs touch events, but it doesn't work for me ...
I even changed the size of the CustomView so that it covers the whole screen, but it still doesn't work, and it cannot even cover my button.
The codes I use are attached below. When run on the device, both the button and the status bar work - nothing is blocked.
Am I missing something?
Codes
In AndroidManifest.xml:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:supportsRtl="true"
android:theme="#android:style/Theme.Holo.NoActionBar.Fullscreen">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
In activity_main.xml:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:id="#+id/text_show" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click"
android:id="#+id/button_click"
android:onClick="changeText"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true" />
In MainActivity.java:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
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;
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) (50 * getResources()
.getDisplayMetrics().scaledDensity);
localLayoutParams.format = PixelFormat.TRANSPARENT;
CustomViewGroup view = new CustomViewGroup(this);
manager.addView(view, localLayoutParams);
setContentView(R.layout.activity_main);
}
boolean key = false;
public void changeText(View view) {
TextView tv = (TextView) findViewById(R.id.text_show);
if (key) {
tv.setText("hahaha");
} else {
tv.setText("eroero");
}
key = ! key;
}
In CustomViewGroup (copied from the above link):
public class CustomViewGroup extends ViewGroup {
public CustomViewGroup(Context context) {
super(context);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.v("CustomViewGroup", "**********Intercepted");
return true;
}
}
Finally the best I can do is to use the Task Lock feature introduced in Android 5.0.
Reference: startLockTask.
The issues of this method:
Unless you have a helper app that grant lock task permission to your full screen app, the user will be asked if (s)he allows the lock.
Once locked, the user can still use physical buttons (home, back, volumn, etc.).
Since my intention is not to have a kiosk mode, I don't really care about point 2.
Point 1 is also acceptable, but a bit annoying since it will (and should) be asked every time onResume is called.
This can be solved by setting a service app as device owner, which grants permission to apps that demand it. But the user has to do this him(her)self (c.f. this answer), which is reasonable, otherwise an app would be able to totally kidnap your device.
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'm trying to make a custom navigation button and have disabled the default navigation buttons provided by android by rooting my device. I want my custom navigation buttons to disappear after some interval of time (say 5 seconds). I have managed to do so. I want to make something such that whenever I touch anywhere on the screen, I can detect the touch event and show my navigation bar. Whether I'm on homescreen or any application, I can receive touch event. Is there a way to do so or do I need to go android source code?
Thank you
OnCreate of your Service: used WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH flag.
#Override
public void onCreate() {
super.onCreate();
Toast.makeText(getBaseContext(),"onCreate", Toast.LENGTH_LONG).show();
mView = new HUDView(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(mView, params);
}
Now, you will start getting each and every click event.
see this Creating a system overlay window (always on top)
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);.
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.