Это новая рубрика — как сделать приложение, где мы с вами будем учиться делать простые приложения для 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 если его не используем?
Привет всем я начинаюший прогромист.