Android:完全控制手机(Kiosk模式),有可能吗? 怎么样?

我们有一个程序,我们安装在手机上,并将手机租借给用户一段时间。 我们希望手机只用于运行我们的应用程序(没有电话,没有游戏,没有任何东西)。 手机将被植根。

所以我们需要的东西是:

  • 全屏运行,没有其他可见的
  • 主页button和其他设备button将不起作用
  • 我们的应用程序将启动时自动运行

它不必是“黑客certificate”,但应足以防止普通用户搞乱设备。

这可能吗? 我在Symbian和Windows Mobile上做了类似的事情,但是我没有太多有关Android上的东西的经验。 这怎么可能实现呢?

2015年更新:如果你不介意限制你的应用程序到单一的手机厂商,三星已经推出了KNOX SDK,可以让你实现Kiosk模式,更简单,而不需要根植电话。 详情请参阅: https : //seap.samsung.com/developer/sdk/knox-standard-android

Solutions Collecting From Web of "Android:完全控制手机(Kiosk模式),有可能吗? 怎么样?"

是的,这是可能的,但你不能控制Home keyend call key的行为。

为全屏添加android:theme="@android:style/Theme.NoTitleBar.Fullscreen"到manifest文件中的activity标签。

要禁用来电,您需要听电话:

 import android.app.Service; import android.os.IBinder; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; public class MyPhoneStateListener extends Service{ @Override public IBinder onBind(Intent arg0) { return null; } @Override public void onCreate() { super.onCreate(); StateListener phoneStateListener = new StateListener(); TelephonyManager telephonymanager = (TelephonyManager)getSystemService(TELEPHONY_SERVICE); telephonymanager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); } class StateListener extends PhoneStateListener{ @Override public void onCallStateChanged(int state, String incomingNumber) { super.onCallStateChanged(state, incomingNumber); switch(state){ case TelephonyManager.CALL_STATE_RINGING: //Disconnect the call here... break; case TelephonyManager.CALL_STATE_OFFHOOK: break; case TelephonyManager.CALL_STATE_IDLE: break; } } }; @Override public void onDestroy() { } } 

注意:在停止服务时,不要去掉监听器并将这些权限添加到清单文件中:

 <uses-permission android:name="android.permission.READ_PHONE_STATE" /> 

并以编程方式断开通话:

 try{ TelephonyManager manager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE); Class c = Class.forName(manager.getClass().getName()); Method m = c.getDeclaredMethod("getITelephony"); m.setAccessible(true); ITelephony telephony = (ITelephony)m.invoke(manager); telephony.endCall(); } catch(Exception e){ Log.d("",e.getMessage()); } 

注意:添加此文件以断开通话: http : //dl.dropbox.com/u/31740476/ITelephony.aidl

要禁用键,您需要覆盖:

 @Override public boolean dispatchKeyEvent(KeyEvent event) { if(KeyEvent.KEYCODE_MENU == event.getKeyCode() || KeyEvent.KEYCODE_DPAD_LEFT==event.getKeyCode() || KeyEvent.KEYCODE_DPAD_DOWN==event.getKeyCode() || KeyEvent.KEYCODE_DPAD_RIGHT==event.getKeyCode() || KeyEvent.KEYCODE_DPAD_UP==event.getKeyCode() || KeyEvent.KEYCODE_DPAD_CENTER==event.getKeyCode() || KeyEvent.KEYCODE_BACK==event.getKeyCode()) { return false; } return true; } 

在主页按下主屏幕将出现,所以要克服这一点,你需要实现一个服务,那里你需要实现一个无限的线程来重新启动你的应用程序是这样的:

 public class AppTrackingService extends Service { private RunnableThread thread; private Context ctx; @Override public IBinder onBind(Intent intent) { return null; } public void onCreate(){ super.onCreate(); ctx = AppTrackingService.this; thread = new RunnableThread(); } public void onStart(Intent intent, int startid) { try{ if(thread==null) thread = new RunnableThread(); thread.startThread(); }catch(Exception e){ } } class RunnableThread extends Thread { Handler back_handler = new Handler(); boolean isContinue = false; public RunnableThread(){ isContinue = false; } public void setIsContinue(boolean val){ this.isContinue = val; } public void startThread(){ isContinue = true; start(); } public void run(){ ActivityManager actMngr = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); while(isContinue){ try{ //Maintain a boolean "isyourapprunning" to know if your app was running or not.... if(isyourapprunning){ String runningPkg = actMngr.getRunningTasks(1).get(0).topActivity.getPackageName(); if (!runningPkg.equals(ctx.getPackageName())){ launchApp(ctx.getPackageName()); } Thread.sleep(2500); //2.5 secs }else{ isContinue = false; stopSelf(); } }catch(Exception e){ } }//end of while loop } protected void launchApp(String packageName) { Intent mIntent = getPackageManager().getLaunchIntentForPackage(packageName); mIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); mIntent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); if (null != mIntent) { try { startActivity(mIntent); } catch(Exception e) { } } } } } 

编辑

您需要添加以下权限才能结束呼叫:

 <uses-permission android:name="android.permission.CALL_PHONE" /> 

你可以使用下面的AIDL文件:

 package com.android.internal.telephony; /** * Interface used to interact with the phone. Mostly this is used by the * TelephonyManager class. A few places are still using this directly. * Please clean them up if possible and use TelephonyManager instead. * * {@hide} */ interface ITelephony { /** * End call if there is a call in progress, otherwise does nothing. * * @return whether it hung up */ boolean endCall(); /** * Silence the ringer if an incoming call is currently ringing. * (If vibrating, stop the vibrator also.) * * It's safe to call this if the ringer has already been silenced, or * even if there's no incoming call. (If so, this method will do nothing.) * * TODO: this should be a oneway call too (see above). * (Actually *all* the methods here that return void can * probably be oneway.) */ void silenceRinger(); } 

Vineet的解决scheme工作。 不过,我认为这需要两个更多的权限,我从这里find

所以需要的权限是

android.permission.READ_PHONE_STATE,android.permission.MODIFY_PHONE_STATE,android.permission.CALL_PHONE

尽pipe它对我来说是这样的

<uses-permission android:name="android.permission.READ_PHONE_STATE"/>

<uses-permission android:name="android.permission.CALL_PHONE"/>

你也可以看看这个: https : //github.com/ligi/Setec-Astronomy对于无羞耻的自我插件感到抱歉,但我们有类似的问题;-)

@Vineet Shukla: READ_PHONE_STATE权限是不够的,使其工作。 您还需要CALL_PHONE权限才能结束通话。

 <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.CALL_PHONE"/> 

MODIFY_PHONE_STATE (如Zaki Choudhury所说)是一个系统权限,只能在根用户的设备上使用,并且在代码的任何部分都不需要。