【Android】超级手电筒项目总结(上)

一、项目教程链接:http://study.163.com/course/courseMain.htm?courseId=897003

与教程源码略有不同。


二、涉及功能点:

1.控制闪光灯实现手电筒的功能;

2.实现屏幕上灯光图的交替闪烁;

3.使用闪光灯的亮与灭发送莫尔斯电码;

4.使用高亮度纯色背景充当另一种手电功能。


三、涉及的技术:

1.控制闪光灯的亮与灭;

2.获取和设置屏幕亮度;

3.UI线程和非UI线程通讯;

4.自定义控件——颜色选择对话框


四、项目结构:

  目前采用继承链的结构,即BaseActivity→ColorLight→WarningLight

MorseCodeLight→ColorLight→Setting→MainActivity。其中BaseActivity获取通用控件并处理公共方法,Setting设置闪烁频率和管理快捷方式,MainActivity进行功能的选择以及相应Layout的加载隐藏,其余均为相关功能点。


五、功能点部分代码:

1.BaseActivity

protected enum UIType {
        //使用枚举类型记录每个Layout,方便在加载和隐藏时使用
        UI_TYPE_MAIN,
        UI_TYPE_FLASHLIGHT,
        UI_TYPE_WARNINGLIGHT,
        UI_TYPE_MORSECODELIGHT,
        UI_TYPE_COLORLIGHT,
        UI_TYPE_SETTING
    }
    //设置起始Layout为FlashLight的Layout
    protected UIType currentUIType = UIType.UI_TYPE_FLASHLIGHT;
    protected UIType lastUIType = UIType.UI_TYPE_FLASHLIGHT;
    //返回键点击次数,用于“再按一次退出”功能
    protected int finishCount;

protected void hideAllUI() {
        //隐藏所有Layout,再根据功能点加载相应的Layout
        main_ui.setVisibility(View.GONE);
        flashnight_ui.setVisibility(View.GONE);
        warninglight_ui.setVisibility(View.GONE);
        morsecodelight_ui.setVisibility(View.GONE);
        colorlight_ui.setVisibility(View.GONE);
        setting_ui.setVisibility(View.GONE);
    }

    protected void setScreenBrightness(float value) {
        //设置屏幕亮度,value取值0-1,0表最暗,1表最亮
        WindowManager.LayoutParams layoutParams = getWindow().getAttributes();
        layoutParams.screenBrightness = value;
        getWindow().setAttributes(layoutParams);
    }

    protected float getDefaultScreenBrightness() {
        //获取当前屏幕亮度
        int value = 0;
        try {
            //获取系统参数:亮度,范围0-255,int型
            value = Settings.System.getInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS);
        } catch (Settings.SettingNotFoundException e) {
            e.printStackTrace();
        }
        return value/255f;
    }

    @Override
    public void finish() {
        //结合重写的dispatchTouchEvent方法完成“再按一次退出”功能
        finishCount++;
        if (finishCount == 1) {
            Toast.makeText(this, "再按一次退出",Toast.LENGTH_SHORT).show();
        } else if (finishCount == 2) {
            super.finish();
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        //当点击屏幕时(未连续两次点击返回),返回点击次数清零
        finishCount = 0;
        return super.dispatchTouchEvent(ev);
    }

2.FlashLight:

public class FlashLight extends BaseActivity {

    private ImageView imageView;
    private Camera camera;
    private Camera.Parameters parameters;
    //通过安卓drawable资源文件的使用来减少Java代码
    private TransitionDrawable transitionDrawable;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        imageView = (ImageView) findViewById(R.id.image_flashnight);
        transitionDrawable = (TransitionDrawable) imageView.getDrawable();
        imageView.setTag(false);
        imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                /*if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)) {
                    Toast.makeText(FlashLight.this, "设备没有闪光灯", Toast.LENGTH_SHORT).show();
                } else {
                    //因模拟器没有闪光灯,故此处逻辑注释掉
                }*/
                if ((Boolean) imageView.getTag()) {
                    closeLight();
                } else {
                    openLight();
                }
            }
        });
    }
    //打开闪光灯
    protected void openLight() {
        //正向动画转换,转换时长200毫秒
        transitionDrawable.startTransition(200);
        imageView.setTag(true);
        camera = Camera.open();
        try {
            camera.setPreviewTexture(new SurfaceTexture(0));
            camera.startPreview();
            parameters = camera.getParameters();
            parameters.setFlashMode(parameters.FLASH_MODE_TORCH);
            camera.setParameters(parameters);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //关闭闪光灯
    protected void closeLight() {
        if ((Boolean) imageView.getTag()) {
            //反向动画转化
            transitionDrawable.reverseTransition(200);
            imageView.setTag(false);

            if (camera != null) {
                parameters = camera.getParameters();
                parameters.setFlashMode(parameters.FLASH_MODE_OFF);
                camera.setParameters(parameters);
                camera.stopPreview();
                camera.release();
                camera = null;
            }
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        closeLight();
    }
}
其中,ImageView使用的flashlight.xml,可减少Java代码的使用,具体如下:



    
    


3. WarningLight:

public class WarningLight extends FlashLight {

    private ImageView warningImage_1;
    private ImageView warningImage_2;
    // 此处之所以设置为protected,因为在MainActivity中会用到此变量
    protected boolean flicker = true;  //true:闪烁,false:停止闪烁。
    private boolean state = true;  //true:on→off, false:off→on

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        warningImage_1 = (ImageView) findViewById(R.id.warningImage_1);
        warningImage_2 = (ImageView) findViewById(R.id.warningImage_2);
    }

    class WarningLightThread extends Thread {
        @Override
        public void run() {
            super.run();
            while (flicker) {
                try {
                    Thread.sleep(warninglight_interval);
                    warningHanlder.sendEmptyMessage(0);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private Handler warningHanlder = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            if (state) {
                warningImage_1.setImageResource(R.drawable.flashlight_off);
                warningImage_2.setImageResource(R.drawable.flashlight_on);
                state = false;
            } else {
                warningImage_1.setImageResource(R.drawable.flashlight_on);
                warningImage_2.setImageResource(R.drawable.flashlight_off);
                state = true;
            }
        }
    };
}

3. MorseCodeLight:

public class MorseCodeLight extends WarningLight {

    //闪光灯在“点”保持亮度时长,单位毫秒
    private static final int DOT_TIME = 200;
    //“划”时长
    private static final int LINE_TIME = DOT_TIME * 3;
    //点滑间隔时长
    private static final int DOT_LINE_TIME = DOT_TIME;
    //字符间隔
    private static final int CHAR_CHAR_TIME = LINE_TIME;
    //单词间隔
    private static final int WORD_WORD_TIME = DOT_TIME * 7;
    private EditText morsecodelight_edittext;
    private String morseCode;
    //使用HashMap存储莫尔斯电码表
    private Map morseCodeMap = new HashMap<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        morsecodelight_edittext = (EditText) findViewById(R.id.morsecodelight_edittext);
        morseCodeMap.put('a', ".-");
        morseCodeMap.put('b', "-...");
        morseCodeMap.put('c', "-.-.");
        morseCodeMap.put('d', "-..");
        morseCodeMap.put('e', ".");
        morseCodeMap.put('f', "..-.");
        morseCodeMap.put('g', "--.");
        morseCodeMap.put('h', "....");
        morseCodeMap.put('i', "..");
        morseCodeMap.put('j', ".---");
        morseCodeMap.put('k', "-.-");
        morseCodeMap.put('l', ".-..");
        morseCodeMap.put('m', "--");
        morseCodeMap.put('n', "-.");
        morseCodeMap.put('o', "---");
        morseCodeMap.put('p', ".--.");
        morseCodeMap.put('q', "--.-");
        morseCodeMap.put('r', ".-.");
        morseCodeMap.put('s', "...");
        morseCodeMap.put('t', "-");
        morseCodeMap.put('u', "..-");
        morseCodeMap.put('v', "...-");
        morseCodeMap.put('w', ".--");
        morseCodeMap.put('x', "-..-");
        morseCodeMap.put('y', "-.--");
        morseCodeMap.put('z', "--..");
        morseCodeMap.put('0', "-----");
        morseCodeMap.put('1', ".----");
        morseCodeMap.put('2', "..---");
        morseCodeMap.put('3', "...--");
        morseCodeMap.put('4', "....-");
        morseCodeMap.put('5', ".....");
        morseCodeMap.put('6', "-....");
        morseCodeMap.put('7', "--...");
        morseCodeMap.put('8', "---..");
        morseCodeMap.put('9', "----.");
        morseCodeMap.put('.', ".-.-.-");
        morseCodeMap.put(',', "--..--");
        morseCodeMap.put('?', "..--..");

        findViewById(R.id.morsecodelight_checkbutton).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                morseCode = morsecodelight_edittext.getText().toString().toLowerCase();
                if (verifyMorseCode()) {
                    sendSentence(morseCode);
                }
            }
        });
        final FadedTextView fadedTextView = (FadedTextView) findViewById(R.id.fadedtextview);
        fadedTextView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                fadedTextView.hideText();
            }
        });
    }

    private void sleep(long t) {
        try {
            Thread.sleep(t);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //发送点
    private void sendDot() {
        openLight();
        sleep(DOT_TIME);
        closeLight();
    }

    //发送线
    private void sendLine() {
        openLight();
        sleep(LINE_TIME);
        closeLight();
    }

    //发送字符
    private void sendChar(char c) {
        String morseCode = morseCodeMap.get(c);
        if (!morseCode.isEmpty()) {
            char single_char;
            for (int i = 0; i < morseCode.length(); i++) {
                single_char = morseCode.charAt(i);
                switch (single_char) {
                    case '.':
                        sendDot();
                        break;
                    case '-':
                        sendLine();
                        break;
                }
                if (i < morseCode.length() - 1) {
                    sleep(DOT_LINE_TIME);
                }
            }
        }
    }

    //发送单词
    private void sendWord(String s) {
        for (int i = 0; i < s.length(); i++) {
            sendChar(s.charAt(i));
            if (i < s.length() - 1) {
                sleep(CHAR_CHAR_TIME);
            }
        }
    }

    //发送句子
    private void sendSentence(String s) {
        //使用正则表达式划分句子为单词数组
        String[] words = s.split(" +");
        for (int i = 0; i < words.length; i++) {
            sendWord(words[i]);
            if (i < words.length - 1) {
                sleep(WORD_WORD_TIME);
            }
        }
        Toast.makeText(this, "莫尔斯电码发送完成", Toast.LENGTH_SHORT).show();
    }
    
    //判断输入合法性
    private boolean verifyMorseCode() {
        if ("".equals(morseCode)) {
            Toast.makeText(this, "请输入", Toast.LENGTH_SHORT).show();
            return false;
        } else {
            for (int i = 0; i < morseCode.length(); i++) {
                char c = morseCode.charAt(i);
                if (!(c >= 'a' && c <= 'z') &&
                        !(c >= '0' && c <= '9') &&
                        c != ' ' &&
                        c != ',' &&
                        c != '.' &&
                        c != '?') {
                    Toast.makeText(this, "只能包含数字字母和,.?", Toast.LENGTH_SHORT).show();
                    return false;
                }
            }
            return true;
        }
    }
}






你可能感兴趣的:(【Android】超级手电筒项目总结(上))