I am working on an android application where I use a custom view to my window. I have the following code to do it :-
private void systemOverlayFullScreen()
{
WindowManager manager = ((WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE));
//manager.removeView(view);
WindowManager.LayoutParams localLayoutParams = new WindowManager.LayoutParams();
// changed to alerts or overlay from system_error
localLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
// set width and height of overlay originally -1
localLayoutParams.width = -1;
// changed gravity to bottom so as to hide the stop the home button press; originally -1
localLayoutParams.height = -1;
localLayoutParams.y = -getNavigationBarHeight();
localLayoutParams.x = 0;
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;
// you can change it to transparent
//localLayoutParams.format = PixelFormat.TRANSLUCENT;
localLayoutParams.alpha = 0.3f;
CustomViewGroup view = new CustomViewGroup(this);
manager.addView(view, localLayoutParams);
}
When I click the home button and then relaunch my app again, the previously added custom view is still present. I want to remove it when the app relaunches.
I have tried doing :-
#Override
protected void onRestart() {
// TODO Auto-generated method stub
super.onRestart();
if(view.getWindowToken() != null)
{
Toast.makeText(getApplicationContext(), "View present", Toast.LENGTH_SHORT).show();
WindowManager manager = ((WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE));
manager.removeView(view);
}
else
{
Toast.makeText(getApplicationContext(), "View not present", Toast.LENGTH_SHORT).show();
}
}
But this doesnot work.
Can anyone tell me how to remove a view dynamically when the app starts ?
Your code will execute exactly as specified when you open the app everytime. Meaning it will add the CustomView once the app is opened. The onRestart method takes into account the activity restart not the whole app. You could perform a check before adding the view. i.e the user enters there name and you store it SharedPreferences. Then you can test if the user signed up and if they did it means when theres a restart the CustomView won't be added to your window.
Related
I got a problem when I tried to close the notification bar from my application.
here is where i try to close it
#Override
public void onWindowFocusChanged(boolean hasFocus)
{
Log.i("FocusChanged", "Focus changed");
if(!hasFocus)
{
Log.e("Focus debug", "Lost focus !");
// Close every kind of system dialog
Intent closeDialog = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
getApplicationContext().sendBroadcast(closeDialog);
Log.i("FocusChanged", "Focus changed - iam supposed to close this dialogs");
}
super.onWindowFocusChanged(hasFocus);
}
But it don't work.
Unless if I add a breakpoint to the function.
Everytime that i open the system notification i got the log that say "Focus changed" so my app run the code, but hasFocus not set to true, or as I said only if i ran the debugger and set breakpoint in the function.
We could not prevent the status appearing in full screen mode in kitkat devices, so made a hack which still suits the requirement ie block the status bar from expanding.
For that to work, the app was not made full screen. We put a overlay over status bar and consumed all input events. It prevented the status from expanding.
note:
customViewGroup is custom class which extends any layout(frame,relative layout etc) and consumes touch event.
to consume touch event override the onInterceptTouchEvent method of the view group and return true
You also need to set the android permission
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
You need an extended ViewGroup class to handle Touch Event
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;
}
}
in the activity where you want to disable the notification bar you need to add this function (don't forget to add field variable CustomViewGroup blockingView)
private void disableNotificationBar(){
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;
blockingView = new CustomViewGroup(this);
manager.addView(blockingView, localLayoutParams);
}
and then in you onCreate you need to call
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
....
disableNotificationBar();
}
You need to remove it on the onDestroy() to be able to close your application
#Override
protected void onDestroy() {
super.onDestroy();
if (blockingView!=null) {
WindowManager manager = ((WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE));
manager.removeView(blockingView);
}
}
You also need to adjust the overlay size, according to previous answer 40 is enought, but you don't want to prevent user from doing action on your own app, if overlay is to height it will intercept event on your Activity too.
Also in android version > to 5.1 you need an extra permission from the user, add this on your onCreate function insted of the function call
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(this)) {
Toast.makeText(this, "Please give my app this permission!", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE);
} else {
disableNotificationBar();
}
}
else {
disableNotificationBar();
}
I'm using following code for hiding status bar with full screen purpose:
void HideEverything(){
if (Build.VERSION.SDK_INT < 16) {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
} else {
View decorView = getWindow().getDecorView();
// Hide the status bar.
int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);
// Remember that you should never show the action bar if the
// status bar is hidden, so hide that too if necessary.
ActionBar actionBar = getActionBar();
actionBar.hide();
}
}
It shows Screen in full-screen mode but when I touch status bar it shows status bar.
I tried other options to add the full screen and no title bar theme in application and activity level in manifest, but still results are the same... :(
I don't want to show status bar at any step.
How to achieve this in android?
Edit :
Android OS version is 4.4.2
(Above code is working on 4.3 but not on 4.4.2)
Update:
Problem has been solved...
Answer is written below separately...
No solution could work for the problem as Android version is 4.4.2.
As commented by #Academy of Programmer; this solution does not work on Android 6 and above.
But as per the suggestion by Sunny, problem has been solved by preventing the expansion of status bar.
Solution is:
Write an inline customViewGroup class in your main activity.
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;
}
}
Now in your onCreate method of mainActivity add following code before setContentView() :
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 receive 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);
Above code will disable the expansion of status bar.
Now make full screen by following code, add it just below the above code and before the setContentView :
//fullscreen
requestWindowFeature(Window.FEATURE_NO_TITLE);
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
Now in manifest add the permission:
<!-- prevent expanding status bar -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
and you are done.... :)
drawback : This code disables expansion of status bar for the device not just for an activity or an application, so use it if you really need it.
Thank you for all the solutions and suggestions... :)
We cannot prevent the status appearing in full screen mode in kitkat or above devices, so try a hack to block the status bar from expanding.
For an idea, put an overlay over status bar and consume all input events. It will prevent the status bar from expanding.
Using below code you can use full screen ;
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
Write below code above setcontentview.
Note : Don't give any theme to this activity.
Hope this helps.
use following code onCreate
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
I'm created WindowPopup, with edittext. And when i focused on it, soft keyboard show and displace this popup above the top bounds, so i can't see what i'm typing. I want to show keyboard without any displace of views, just above them.
I read that i can change softInputMode for it, so i'm created class which extends from EditText, and tried to change inputMode in onFocusListener, but it didn't help.
setOnFocusChangeListener(new OnFocusChangeListener() {
#Override
public void onFocusChange(View veiw, boolean has_focus) {
if (has_focus) {
//Try to change input mode to prevent displacing
((Activity) getContext()).getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
} else {
//.. return back previous input mode
}
});
I did so, because i need such behavior only in this popup, but i even try to change action attribute in my manifets file
android:windowSoftInputMode="adjustNothing"
or
android:windowSoftInputMode="stateHidden"
Can i show keyboard without any displacing of view?
P.S. i'm using Android API 15
When PopupWindow creates popup view, it sets to it new WindowManager.LayoutParams with softInputMode, which is overwrites behavior of Window.softInputMode. Here piece of code from PopupWindow
private WindowManager.LayoutParams createPopupLayout(IBinder token) {
WindowManager.LayoutParams p = new WindowManager.LayoutParams();
p.gravity = Gravity.LEFT | Gravity.TOP;
p.width = mLastWidth = mWidth;
p.height = mLastHeight = mHeight;
if (mBackground != null) {
p.format = mBackground.getOpacity();
} else {
p.format = PixelFormat.TRANSLUCENT;
}
p.flags = computeFlags(p.flags);
p.type = mWindowLayoutType;
p.token = token;
/*mSoftInputMode is the private field which is by default equals
to WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED
*/
p.softInputMode = mSoftInputMode;
}
So to change softInputMode you need just to call public method of PopupWindow
setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
And there is no need to remember previous soft input method, because this behavior will be only for this PopupWindow
Is there anyway to prevent users from sliding the status bar (expand) or collapsing back?
I'm trying out a lockscreen replacement and seems like it's a must-have feature. Is there any possible way to do it without requiring root privileges?
You can actually prevent the status bar from expanding, without rooting phone. See this link. This draws a window the height of the status bar and consumes all touch events.
Call the following code just after onCreate().
public static void preventStatusBarExpansion(Context context) {
WindowManager manager = ((WindowManager) context.getApplicationContext()
.getSystemService(Context.WINDOW_SERVICE));
Activity activity = (Activity)context;
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;
//https://stackoverflow.com/questions/1016896/get-screen-dimensions-in-pixels
int resId = activity.getResources().getIdentifier("status_bar_height", "dimen", "android");
int result = 0;
if (resId > 0) {
result = activity.getResources().getDimensionPixelSize(resId);
}
localLayoutParams.height = result;
localLayoutParams.format = PixelFormat.TRANSPARENT;
customViewGroup view = new customViewGroup(context);
manager.addView(view, localLayoutParams);
}
public static 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;
}
}
Short answer: this is impossible!
Now should you be interested to know why this is impossible:
There are two permissions for manipulating the system status bar, EXPAND_STATUS_BAR and STATUS_BAR. The former can be requested by any application, but the later is reserved for applications signed with the platform signature (system applications, not third-party). It is possible to expand/ collapse the system status bar (see "How to open or expand status bar through intent?") but note that reflection is required because the StatusBarManager class is not part of the SDK. The disable method, which is used by the Android dialer to prevent the status bar from being expanded, cannot be accessed by an application without the aforementioned STATUS_BAR permission.
Sources: personal experience :-)
First of all, it's impossible to modify the Status Bar if your app is not signed with the phone's rom certified, if you try to modify it you'll get an Security Exception.
Update: In new APIs the method is "collapsePanels" instead of "collapse".
The only way I've found after several hours of work is by overriding the "onWindowFocusChanged" method of the activity and when it loses the focus (maybe the user has touched the notifications bar), force to collapse the StatusBar, here is the code (working on a Defy+ 2.3.5).
You need to declare the following permission on the manifest:
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR"/>
And override the following method:
public void onWindowFocusChanged(boolean hasFocus)
{
try
{
if(!hasFocus)
{
Object service = getSystemService("statusbar");
Class<?> statusbarManager = Class.forName("android.app.StatusBarManager");
Method collapse = statusbarManager.getMethod(Build.VERSION.SDK_INT > 16 ? "collapsePanels" : "collapse");
collapse.setAccessible(true);
collapse.invoke(service);
}
}
catch(Exception ex)
{
}
}
Update: You will have to use your own custom Alert Dialog by overriding it their onWindowFocusChanged method too, because Alert Dialogs have their own focus.
This actually can be done via a little hack that I accidentally discovered, but requires the permission android.permission.SYSTEM_ALERT_WINDOW:
What you do is add a view the exact size of the status bar directly to the WindowManager with the certain parameters that covers the status bar and prevents it from receiving touch events:
View disableStatusBarView = new View(context);
WindowManager.LayoutParams handleParams = new WindowManager.LayoutParams(
WindowManager.LayoutParams.FILL_PARENT,
<height of the status bar>,
// This allows the view to be displayed over the status bar
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
// this is to keep button presses going to the background window
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,
PixelFormat.TRANSLUCENT);
handleParams.gravity = Gravity.TOP;
context.getWindow().addView(disableStatusBarView, handleParams);
This will basically create a transparent view over the status bar that will receive all the touch events and block the events from reaching the status bar and therefore prevents it from being expanded.
NOTE: This code is untested, but the concept works.
I tried the solutions mentioned by GrantLand and PoOk but both didn't work in my case. Though, Another solution Clear/Hide Recent Tasks List did the trick for me. I am writing a launcher app for which I had to disable a recent applications menu so user cannot open a locked app from it. Also, I had to prevent against notification bar expansion and this trick made me achieve both. Override OnWindowFocusChanged method in your activity and check if this is what u wanted.
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
Log.d("Focus debug", "Focus changed !");
if(!hasFocus) {
Log.d("Focus debug", "Lost focus !");
Intent closeDialog = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
sendBroadcast(closeDialog);
}
}
For a lockscreen Why don't you just use the following in your main activity:
#Override
public void onAttachedToWindow() {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
}
If the user doesn't have a secure lockscreen set the app will let the user pull the status bar down and open activities but that doesn't matter as the user obviously doesn't want a secure screen anyway.
If the user does have a secure locksreen set then the app will show the status bar but will not allow interactions with it. This is because the phone is still actually locked and only your activity is allowed to operate until the user unlocks the phone. Also closing your app in anyway will open the standard secure lockscreen. All this is highly desirable because you don't have to spend all that time coding secure features that you can't guarantee will be as secure as the stock ones.
If you really don't want the user to be able to interact with the status bar, maybe you can leave out the flag FLAG_DISMISS_KEYGUARD call. Then just before you are about to unlock the phone set the flag like I showed in the first block. I don't know if this last part works but it's worth a try.
Hope that helps
Sorry but it does not work. using FLAG_LAYOUT_IN_SCREEN prevents you from catching any touch events.
And BTW:
to add a view to the window use the window manager:
WindowManager winMgr = (WindowManager)getSystemService(WINDOW_SERVICE);
winMgr.addView(disableStatusBar, handleParams);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
I'm in the process of developing an Android app for which I need to add a button on the incoming call screen. Is it possible to add a new button to the existing incoming call screen or should I create a custom screen specific to my app?
Edit:
I want to add a button in addition to the Answer and Decline buttons in the screen that appears when there is an incoming call.
I was looking for the same funcionality and found this open source project, http://code.google.com/p/incomingcallplus/
Haven't played with it yet, but seems to do what you're looking for.
Yes and No.
No, you can't add a new button to an existing app. But Yes, you can replace that app (in this case, the dialer) with one that has the button you want. When users install your app, they'll pick whether they want to use your app or the built-in dialer app to make and receive calls.
You probably want to add something like the following to your main.xml:
<Button android:id="#+id/helloButton" android:layout_height="wrap_content" android:layout_width="wrap_content" text="Hello Button" />
Then in your 'Launcher' activity, you'll need to assign a handler to handle clicks, etc.
If you want to do this on the default dialer screen then I don't think that's possible without disabling controls of the dialer and having your transparent activity over the dialer; user will be able to interact with your activity and can only use the dialer on clicking the back button.
You might want to go with the custom design.
public void addInvitePopup(final String number,Context c){
//check if pref is ok with invite in call
// if(!Preferences.getInstance(c.getInviteInCall())){return ; }
// sets the WindowManager
WindowManager wm = (WindowManager) c.getSystemService(Context.WINDOW_SERVICE);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT |
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
params.x = 250;
params.height = LayoutParams.WRAP_CONTENT;
params.width = LayoutParams.WRAP_CONTENT;
params.format = PixelFormat.TRANSLUCENT;
final Context ct =c;
params.gravity = Gravity.TOP;
params.setTitle("Testing");
LinearLayout ly = new LinearLayout(c);
ly.setOrientation(LinearLayout.VERTICAL);
Button inviteButton = new Button(c);
inviteButton.setClickable(true);
inviteButton.setBackgroundDrawable(c.getResources().getDrawable(R.drawable.icon));
inviteButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(v.getContext(), "adding to blacklist..", Toast.LENGTH_LONG).show();
v.setBackgroundDrawable(ct.getResources().getDrawable(R.drawable.images));
v.setClickable(false);
// sendMessage(v, number);
//Track this event:
//MixPanelTracking.setPropKeyValue(getApplicationContext(), null, null, "Add friend - During Call");
}
});
also dont forget to add permission : android.permission.SYSTEM_ALERT_WINDOW in your manifest file