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

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

所以我们需要的东西是:

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

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

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

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

是的,这是可能的,但你不能控制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所说)是一个系统权限,只能在根用户的设备上使用,并且在代码的任何部分都不需要。