限制通知栏拉动
Restrict Notification Bar from pulling
@Override
public void onWindowFocusChanged(boolean hasFocus){
super.onWindowFocusChanged(hasFocus);
try{
if(!hasFocus && enableKioskMode){
Intent closeDialog = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
sendBroadcast(closeDialog);
ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
am.moveTaskToFront(getTaskId(), ActivityManager.MOVE_TASK_WITH_HOME);
// sametime required to close opened notification area
Timer timer = new Timer();
timer.schedule(new TimerTask(){
public void run() {
Intent closeDialog = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
sendBroadcast(closeDialog);
}
}, 500);
}
}catch(Exception ex){
ex.printStackTrace();
}
}
private 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) {
return true;
}
}
private void addBlockingViews() {
try {
WindowManager manager = ((WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE));
//For Bottom View
WindowManager.LayoutParams bottomlocalLayoutParams = new WindowManager.LayoutParams();
bottomlocalLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
bottomlocalLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
bottomlocalLayoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
bottomlocalLayoutParams.height = (int) (50 * getResources().getDisplayMetrics().scaledDensity);
bottomlocalLayoutParams.format = PixelFormat.RGBX_8888;
bottomlocalLayoutParams.gravity = Gravity.BOTTOM;
bottomView = new CustomViewGroup(BaseActivity.this);
ViewGroup.LayoutParams layoutParams1 = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 50);
bottomView.setLayoutParams(layoutParams1);
manager.addView(bottomView, bottomlocalLayoutParams);
WindowManager.LayoutParams toplocalLayoutParams = new WindowManager.LayoutParams();
toplocalLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
toplocalLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
int resId = getResources().getIdentifier("status_bar_height", "dimen", "android");
int result = 0;
if (resId > 0) {
result = getResources().getDimensionPixelSize(resId);
} else {
// Use Fallback size:
result = 60; // 60px Fallback
}
//toplocalLayoutParams.height = result;
toplocalLayoutParams.height = (int) (50 * getResources().getDisplayMetrics().scaledDensity);
toplocalLayoutParams.gravity = Gravity.TOP;
toplocalLayoutParams.format = PixelFormat.TRANSPARENT;
topView = new CustomViewGroup(BaseActivity.this);
ViewGroup.LayoutParams layoutParams2 = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
25);
topView.setLayoutParams(layoutParams2);
manager.addView(topView, toplocalLayoutParams);
} catch (Exception e) {
e.printStackTrace();
}
}
我的目标是创建一个 Kiosk 应用程序。我检查了很多代码,比如 this and this. With their help I have achieved navigation bar hiding. Now I want to block user from dragging the notification bar down just like Surelock does. I've tried the common answers given in SO posts like here。但它在我的带有 Android Pie 的 Redmi Note 5 Pro 中不起作用。有没有其他方法可以做到这一点?
如果您的信息亭应用程序是设备所有者(如您引用的示例之一所述),您可以使用 DevicePolicyManager.setStatusBarDisabled()
:
Disabling the status bar blocks notifications, quick settings and
other screen overlays that allow escaping from a single use device.
从 Android 6 (API 23) 开始可用,状态栏仍然显示(包括时间、wifi 级别、蓝牙指示器...)但通知不显示而且你无法展开它。
在此解决方案中,通知栏并未完全被阻止,但会在用户打开后关闭。您需要一个检查通知栏是否重复打开的服务。此服务使用反射来获取打开通知栏后关闭通知栏所需的方法,因此我认为它无法在 android 9 台设备上运行(刚刚检查过它在 7.1.1 设备上与 compilesdk 28 一起工作正常)。您需要使用此权限:
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR"/>
这是服务代码:
public class CollapseService extends Service {
ScheduledExecutorService scheduler;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
MyRunnable runnable = new MyRunnable(this);
scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate
(runnable, 0, 100, TimeUnit.MILLISECONDS);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return Service.START_STICKY;
}
private void collapseNow() {
Object statusBarService = getSystemService("statusbar");
Class<?> statusBarManager = null;
try {
statusBarManager = Class.forName("android.app.StatusBarManager");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Method collapseStatusBar = null;
try {
collapseStatusBar = statusBarManager.getMethod("collapsePanels");
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
collapseStatusBar.setAccessible(true);
try {
collapseStatusBar.invoke(statusBarService);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
@Override
public void onDestroy() {
super.onDestroy();
scheduler.shutdown();
}
static class MyRunnable implements Runnable{
CollapseService aService = null;
MyRunnable(CollapseService service){
WeakReference<CollapseService> weakReference = new WeakReference<>(service);
aService = weakReference.get();
}
@Override
public void run(){
if(aService != null) {
aService.collapseNow();
}
}
}
}
弱引用是为了排除内存泄漏发生的可能性。
@Override
public void onWindowFocusChanged(boolean hasFocus){
super.onWindowFocusChanged(hasFocus);
try{
if(!hasFocus && enableKioskMode){
Intent closeDialog = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
sendBroadcast(closeDialog);
ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
am.moveTaskToFront(getTaskId(), ActivityManager.MOVE_TASK_WITH_HOME);
// sametime required to close opened notification area
Timer timer = new Timer();
timer.schedule(new TimerTask(){
public void run() {
Intent closeDialog = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
sendBroadcast(closeDialog);
}
}, 500);
}
}catch(Exception ex){
ex.printStackTrace();
}
}
private 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) {
return true;
}
}
private void addBlockingViews() {
try {
WindowManager manager = ((WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE));
//For Bottom View
WindowManager.LayoutParams bottomlocalLayoutParams = new WindowManager.LayoutParams();
bottomlocalLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
bottomlocalLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
bottomlocalLayoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
bottomlocalLayoutParams.height = (int) (50 * getResources().getDisplayMetrics().scaledDensity);
bottomlocalLayoutParams.format = PixelFormat.RGBX_8888;
bottomlocalLayoutParams.gravity = Gravity.BOTTOM;
bottomView = new CustomViewGroup(BaseActivity.this);
ViewGroup.LayoutParams layoutParams1 = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 50);
bottomView.setLayoutParams(layoutParams1);
manager.addView(bottomView, bottomlocalLayoutParams);
WindowManager.LayoutParams toplocalLayoutParams = new WindowManager.LayoutParams();
toplocalLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
toplocalLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
int resId = getResources().getIdentifier("status_bar_height", "dimen", "android");
int result = 0;
if (resId > 0) {
result = getResources().getDimensionPixelSize(resId);
} else {
// Use Fallback size:
result = 60; // 60px Fallback
}
//toplocalLayoutParams.height = result;
toplocalLayoutParams.height = (int) (50 * getResources().getDisplayMetrics().scaledDensity);
toplocalLayoutParams.gravity = Gravity.TOP;
toplocalLayoutParams.format = PixelFormat.TRANSPARENT;
topView = new CustomViewGroup(BaseActivity.this);
ViewGroup.LayoutParams layoutParams2 = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
25);
topView.setLayoutParams(layoutParams2);
manager.addView(topView, toplocalLayoutParams);
} catch (Exception e) {
e.printStackTrace();
}
}
我的目标是创建一个 Kiosk 应用程序。我检查了很多代码,比如 this and this. With their help I have achieved navigation bar hiding. Now I want to block user from dragging the notification bar down just like Surelock does. I've tried the common answers given in SO posts like here。但它在我的带有 Android Pie 的 Redmi Note 5 Pro 中不起作用。有没有其他方法可以做到这一点?
如果您的信息亭应用程序是设备所有者(如您引用的示例之一所述),您可以使用 DevicePolicyManager.setStatusBarDisabled()
:
Disabling the status bar blocks notifications, quick settings and other screen overlays that allow escaping from a single use device.
从 Android 6 (API 23) 开始可用,状态栏仍然显示(包括时间、wifi 级别、蓝牙指示器...)但通知不显示而且你无法展开它。
在此解决方案中,通知栏并未完全被阻止,但会在用户打开后关闭。您需要一个检查通知栏是否重复打开的服务。此服务使用反射来获取打开通知栏后关闭通知栏所需的方法,因此我认为它无法在 android 9 台设备上运行(刚刚检查过它在 7.1.1 设备上与 compilesdk 28 一起工作正常)。您需要使用此权限:
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR"/>
这是服务代码:
public class CollapseService extends Service {
ScheduledExecutorService scheduler;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
MyRunnable runnable = new MyRunnable(this);
scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate
(runnable, 0, 100, TimeUnit.MILLISECONDS);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return Service.START_STICKY;
}
private void collapseNow() {
Object statusBarService = getSystemService("statusbar");
Class<?> statusBarManager = null;
try {
statusBarManager = Class.forName("android.app.StatusBarManager");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Method collapseStatusBar = null;
try {
collapseStatusBar = statusBarManager.getMethod("collapsePanels");
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
collapseStatusBar.setAccessible(true);
try {
collapseStatusBar.invoke(statusBarService);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
@Override
public void onDestroy() {
super.onDestroy();
scheduler.shutdown();
}
static class MyRunnable implements Runnable{
CollapseService aService = null;
MyRunnable(CollapseService service){
WeakReference<CollapseService> weakReference = new WeakReference<>(service);
aService = weakReference.get();
}
@Override
public void run(){
if(aService != null) {
aService.collapseNow();
}
}
}
}
弱引用是为了排除内存泄漏发生的可能性。