Это новая рубрика – как сделать приложение, где мы с вами будем учиться делать простые приложения для android, опираясь на материал бесплатных уроков нашего канала. Начнем с простого приложения – это фонарик. Приложение состоит из одной кнопки на экране, которая включает и выключает вспышку камеры устройства – если она есть, конечно.
<uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.FLASHLIGHT"/> <uses-feature android:name="android.hardware.camera"/>
Также в активити добавим директиву, которая отключит его пересоздание при повороте экрана:
android:configChanges="orientation|keyboardHidden|screenSize"
Нам понадобятся такие строки, добавьте в res/values/strings.xml:
<resources> <string name="app_name">Фонарик</string> <string name="error_text">Вспышка камеры недоступна!</string> <string name="error_title">Ошибка! Нет вспышки!</string> <string name="exit_message">Выход</string> </resources>
<shape xmlns:android="http://schemas.android.com/apk/res/android"> <gradient android:type="radial" android:startColor="#303030" android:endColor="#050505" android:gradientRadius="450" android:angle="050"/> </shape>
В папку res/raw (создайте, если ее нет) загрузите звук щелчка по ссылке.
В макете экрана приложения такие компоненты:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/flash_background" tools:context="info.fandroid.flashlight.MainActivity"> <Switch android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/my_switch" android:layout_centerInParent="true"/> </RelativeLayout>
Здесь используем экранный компонент Switch – переключатель, выравниваем его по центру.
Теперь код главного класса MainActivity.java:
package ... import android.annotation.TargetApi; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.pm.PackageManager; import android.graphics.SurfaceTexture; import android.hardware.Camera; import android.hardware.Camera.Parameters; import android.media.AudioAttributes; import android.media.AudioManager; import android.media.SoundPool; import android.os.Build; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.widget.CompoundButton; import android.widget.Switch; import java.io.IOException; import java.util.List; public class MainActivity extends AppCompatActivity implements SoundPool.OnLoadCompleteListener { private int sound; private SoundPool soundPool; private Camera camera; Parameters parameters; private Switch mySwitch; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { createSoundPoolWithBuilder(); } else { createSoundPoolWithConstructor(); } soundPool.setOnLoadCompleteListener(this); sound = soundPool.load(this, R.raw.click, 1); mySwitch = (Switch) findViewById(R.id.my_switch); mySwitch.setChecked(true); mySwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) { if (isChecked) { setFlashLigthOn(); } else { setFlashLightOff(); } } }); boolean isCameraFlash = getApplicationContext().getPackageManager() .hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH); if (!isCameraFlash) { showCameraAlert(); } else { camera = Camera.open(); } } private void showCameraAlert() { new AlertDialog.Builder(this) .setTitle(R.string.error_title) .setMessage(R.string.error_text) .setPositiveButton(R.string.exit_message, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { finish(); } }) .setIcon(android.R.drawable.ic_dialog_alert) .show(); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) protected void createSoundPoolWithBuilder() { AudioAttributes attributes = new AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_GAME) .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) .build(); soundPool = new SoundPool.Builder().setAudioAttributes(attributes).setMaxStreams(1).build(); } @SuppressWarnings("deprecation") protected void createSoundPoolWithConstructor() { soundPool = new SoundPool(1, AudioManager.STREAM_MUSIC, 0); } private void setFlashLigthOn() { soundPool.play(sound, 1, 1, 0, 0, 1); new Thread(new Runnable() { @Override public void run() { if (camera != null) { parameters = camera.getParameters(); if (parameters != null) { List supportedFlashModes = parameters.getSupportedFlashModes(); if (supportedFlashModes.contains(Parameters.FLASH_MODE_TORCH)) { parameters.setFlashMode(Parameters.FLASH_MODE_TORCH); } else if (supportedFlashModes.contains(Parameters.FLASH_MODE_ON)) { parameters.setFlashMode(Parameters.FLASH_MODE_ON); } else camera = null; if (camera != null) { camera.setParameters(parameters); camera.startPreview(); try { camera.setPreviewTexture(new SurfaceTexture(0)); } catch (IOException e) { e.printStackTrace(); } } } } } }).start(); } private void setFlashLightOff() { soundPool.play(sound, 1, 1, 0, 0, 1); new Thread(new Runnable() { @Override public void run() { if (camera != null) { parameters.setFlashMode(Parameters.FLASH_MODE_OFF); camera.setParameters(parameters); camera.stopPreview(); } } }).start(); } private void releaseCamera() { if (camera != null) { camera.release(); camera = null; } } @Override protected void onStop() { super.onStop(); releaseCamera(); } @Override protected void onPause() { super.onPause(); releaseCamera(); mySwitch.setChecked(false); } @Override protected void onResume() { super.onResume(); if (camera == null) { camera = Camera.open(); } else{ setFlashLigthOn(); } mySwitch.setChecked(true); } @Override public void onLoadComplete(SoundPool soundPool, int i, int i1) { } }
private void showCameraAlert() { new AlertDialog.Builder( this) .setTitle(R.string. error_title ) .setMessage(R.string. error_text ) .setPositiveButton(R.string. exit_message , new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { finish(); } }) .setIcon(android.R.drawable. ic_dialog_alert ) .show(); }
boolean isCameraFlash = getApplicationContext().getPackageManager() .hasSystemFeature(PackageManager. FEATURE_CAMERA_FLASH); if (!isCameraFlash) { showCameraAlert(); } else { camera = Camera.open(); }
Получаем контекст приложения, PackageManager и выполняем метод hasSystemFeatureс с параметром FEATURE_CAMERA_FLASH. Добавляем условие – если вспышки нет, вызываем метод showCameraAlert(), а если вспышка есть – получаем экземпляр класса Camera.
Звук воспроизводит класс SoundPool. В последнее время рекомендуется создание и настройка экземпляра Soundpool с помощью класса SoundPool.Builder. Soundpool Builder доступен только на API 21+, так что нам нужно будет создать свой Soundpool по разному в зависимости от версии SDK устройства. Для Android 5 и выше будет выполняться этот метод:
@TargetApi (Build.VERSION_CODES. LOLLIPOP) protected void createSoundPoolWithBuilder(){ AudioAttributes attributes = new AudioAttributes.Builder() .setUsage(AudioAttributes. USAGE_GAME ) .setContentType(AudioAttributes. CONTENT_TYPE_SONIFICATION ) .build(); sp = new SoundPool.Builder().setAudioAttributes(attributes).setMaxStreams( 1).build(); }
@SuppressWarnings ("deprecation" ) protected void createSoundPoolWithConstructor(){ sp = new SoundPool( 1, AudioManager. STREAM_MUSIC , 0 ); }
if (Build.VERSION. SDK_INT >= Build.VERSION_CODES. LOLLIPOP ) { createSoundPoolWithBuilder(); } else { createSoundPoolWithConstructor(); } sp .setOnLoadCompleteListener( this); sound = sp .load( this, R.raw. click , 1 );
private void setFlashlightOn() { sp .play( sound, 1, 1, 0, 0, 1); new Thread( new Runnable() { public void run() { if ( camera != null) { params = camera .getParameters(); if( params != null ) { List supportedFlashModes = params .getSupportedFlashModes(); if(supportedFlashModes.contains(Parameters. FLASH_MODE_TORCH )) { params .setFlashMode( Parameters. FLASH_MODE_TORCH ); } else if(supportedFlashModes.contains(Parameters. FLASH_MODE_ON )) { params .setFlashMode( Parameters. FLASH_MODE_ON ); } else camera = null; if( camera != null ) { camera .setParameters( params); camera .startPreview(); try { camera .setPreviewTexture( new SurfaceTexture( 0)); } catch (IOException e) { e.printStackTrace(); } } } } } }).start(); }
private void setFlashlightOff() { sp .play( sound, 1, 1, 0, 0, 1); new Thread( new Runnable() { public void run() { if( camera != null ) { params .setFlashMode(Parameters. FLASH_MODE_OFF); camera .setParameters( params); camera .stopPreview(); } } }).start(); }
mySwitch .setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if(isChecked){ setFlashlightOn(); } else{ setFlashlightOff(); } } });
private void releaseCamera() { if ( camera != null) { camera.release(); camera = null ; } }
@Override protected void onStop() { super .onStop(); releaseCamera(); }
@Override protected void onPause() { super .onPause(); releaseCamera(); mySwitch.setChecked( false); }
@Override protected void onResume() { super .onResume(); if ( camera == null) { camera = Camera. open(); } else { setFlashlightOn(); } mySwitch .setChecked( true); }
При запуске на 7 андроиде пришлось самостоятельно бороться с разрешениями системы, причём такого разрешения как FLASHLIGHT моя студия никак признавать не хотела, всё работает только с android.permission.CAMERA
Для чего мы имплементили интерфейс SoundPool.OnLoadCompleteListener если его не используем?
Привет всем я начинаюший прогромист.