Android:完全控制手机(Kiosk模式),可以吗?怎么样?
我们有一个程序,我们安装在手机上,并在一段时间内将手机借给用户。我们希望手机仅用于运行我们的应用程序(不需要电话,不用游戏,也不需要任何操作)。手机将被植根。Android:完全控制手机(Kiosk模式),可以吗?怎么样?
所以这个事情我们需要:在全屏
- 运行,不出意外将是可见的
- Home键和其他设备的按钮将无法工作
- 我们的应用程序将在启动 自动运行
它不必是“黑客证明”,但应足以防止普通用户弄乱设备。
这可能吗?我在Symbian的& Windows Mobile上做过类似的事情,但我在Android上没有太多经验。这可能如何实现?
UPDATE 2015年:如果你不介意限制你的应用单一的手机厂商,三星推出了KNOX SDK,可以让你实现kiosk模式和更容易生根没有手机。详情请参阅:https://seap.samsung.com/developer/sdk/knox-standard-android
是的,这是可能的,但您无法控制Home key
和end call key
的行为。
全屏添加android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
清单文件中的活动标签。
要禁用来电你要听电话:
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() {
}
}
注:在停止服务不foget删除监听器和这些权限添加到您的清单文件:
<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());
}
注意:将此f ILE断开呼叫: 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;
}
在Home键按下主屏幕会来,所以要克服这一点,你需要实现一个服务有你需要实现一个无限的线程来重新启动您的应用程序是这样的:
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的解决方案的作品。但是我认为,这需要两个权限,我从 here
发现那么所需的权限是
android.permission.READ_PHONE_STATE,android.permission.MODIFY_PHONE_STATE,android.permission.CALL_PHONE
虽然它的工作对我这个样子
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.CALL_PHONE"/>
@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
的(如由扎基乔杜里所述)是一个系统权限,而且可以仅在根设备使用,并且不通过代码的任何部分需要的。
我无法使用.aidl文件。有什么问题吗? –
您需要将.aidl文件添加到您的项目中。您遇到了什么问题?请参阅此链接:http://developer.android.com/guide/developing/tools/aidl。html –
我将该文件添加到我的源项目中,但它在ITelephony telephony =(ITelephony)m.invoke(manager)行中给出错误,而ITelephony未定义。 –