Подтвердить что ты не робот

Android: Полный контроль над телефоном (режим киоска), возможно ли это? Как?

У нас есть программа, которую мы устанавливаем на телефоны и предоставляем пользователям бесплатные телефоны в течение определенного периода времени. Мы хотели бы, чтобы телефоны использовались исключительно для запуска нашего приложения (без телефонных звонков, без игр, без ничего). Телефоны будут укоренены.

Итак, что нам нужно:

  • Запуск в полноэкранном режиме, ничего больше не будет видно
  • Кнопка "Главная" и другие кнопки устройства не будут работать.
  • Наше приложение будет запускаться автоматически при запуске

Это не должно быть "доказательством хакера", но должно быть достаточно, чтобы предотвратить обычное использование пользователя с устройством.

Возможно ли это? Я сделал аналогичные вещи на Symbian и Windows Mobile, но у меня нет большого опыта работы с этим материалом на Android. Как это может быть достигнуто?

UPDATE 2015:. Если вы не возражаете, ограничивая свое приложение единственным поставщиком телефонов, Samsung представила KNOX SDK, который позволяет вам достичь режима киоска и намного проще, не укоряя телефон. Подробнее см.: https://seap.samsung.com/developer/sdk/knox-standard-android

4b9b3361

Ответ 1

Да, это возможно, но вы не можете контролировать поведение 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() {

    }
}

Примечание. В то время как остановка службы не позволяет удалить слушателя и добавить эти разрешения в файл манифеста:

<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 safe to call this if the ringer has already been silenced, or
     * even if there 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();
}

Ответ 2

Работает решение Vineet. Однако я думаю, что это требует еще двух разрешений, которые я узнал из здесь

Таким образом, необходимы следующие разрешения:

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"/>

Ответ 3

вы также можете взглянуть на это: https://github.com/ligi/Setec-Astronomy извините за самозапуск без стыда, но у нас есть похожие проблемы; -)

Ответ 4

@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 (как сказал Заки Чоудхури) является системным разрешением и может использоваться только на корневых устройствах и не требуется какой-либо частью кода.