Создаем программу, ставящую на сигнал звонка случайную мелодию
Главная » Создаем программу, ставящую на сигнал звонка случайную мелодию

Всегда интересно протестировать на своем смартфоне какое то новенькое и необычное приложение, в поисках которого многие проводят долгие часы на Play Market. Сегодня мы сами его создадим. Сделаем такое приложение, которое будет проигрывать случайный рингтон при каждом входящем звонке (даешь каждому входящему вызову - свой рингтон!).

Уровень урока рассчитан на средний уровень владения предметом Android программирования, поэтому здесь не будет слишком много второстепенных деталей, типа объяснений как создать проект.

Приступаем к работе, создаем новый проект, выбираем минимальную версию для запуска Android 2.2 или выше, выбираем Add No Activity и жмем Finish. 

android.permission.READ_PHONE_STATE - для обнаружения входящих вызовов
android.permission.WRITE_SETTINGS - для смены стандартных настроек сигнала вызова
android.permission.READ_EXTERNAL_STORAGE - для выбора списка доступных рингтонов

Приложение будет иметь одно Activity, позволяющее пользователю активировать/дезактивировать изменение рингтона.

<activity android:name=".MainActivity" >
 <intent-filter>
 <action android:name="android.intent.action.MAIN" />
 <category android:name="android.intent.category.LAUNCHER" />
 </intent-filter>
</activity>

Также  в AndroidManifest.xml настроим BroadcastReceiver, который будет обнаруживать изменения состояния вызова. Это будет выполнятся с помощью строки android.intent.action.PHONE_STATE:

<receiver
 android:name=".RingReceiver"
 android:enabled="true">
 <intent-filter>
 <action android:name="android.intent.action.PHONE_STATE"/>
 </intent-filter>
</receiver>

Теперь переходим в файл Stringsxml для добавления туда необходимых строковых ресурсов:

<?xml version="1.0" encoding="utf-8"?>
<resources>
 <string name="app_name">Ringtone Randomizer</string>
 <string name="activate">Activate Ringtone Randomizer</string>
 <string name="deactivate">Deactivate Ringtone Randomizer</string>
 <string name="list_of_ringtones">Ringtones available on this device:</string>
</resources>

Создадим для нашего будущего Activity файл разметки layout. Создаем файл activity_main.xml, он будет содержать элементы:

     - ToggleButton - для активации/дезактивации действия нашего приложения;

     - ListView - для отображения всех доступных рингтонов;

     - TextView - будет использоваться как метка;

Итак, создаем файл в папке layout создаем файл activity_main.xml и помещаем в него следующее:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:orientation="vertical" android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:padding="16dp"
 >
 
 <ToggleButton
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:textOff="@string/activate"
 android:textOn="@string/deactivate"
 android:id="@+id/toggle"
 />
 
 <TextView
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:text="@string/list_of_ringtones"
 android:textStyle="bold"
 />
 
 <ListView
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:id="@+id/list_of_ringtones"
 />
 
</LinearLayout>

Теперь создаем вспомогательный класс RingtoneHelper:

public class RingtoneHelper {
}

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

RingtoneHelper будет иметь два статических метода для работы с RingtoneManager

fetchAvailableRingtones

Метод fetchAvailableRingtones будет предоставлять нам выборку, в виде списка, с доступных рингтонов. 

public static List<Ringtone> fetchAvailableRingtones(Context context){
 
 List<Ringtone> ringtones = new ArrayList<>();
 RingtoneManager mgr = new RingtoneManager(context);
 mgr.setType(RingtoneManager.TYPE_RINGTONE);
 
 int n = mgr.getCursor().getCount();
 for(int i=0;i<n;i++){
 ringtones.add(mgr.getRingtone(i));
 }
 return ringtones;
}

В методу fetchAvailableRingtones мы начали с создания класса RingtoneManager. Объект RingtoneManager может с помощью списка отобразить все звуковые файлы, доступные на устройстве, включая стандартные звуки для будильника, уведомлений и т.п. 

Метод setType мы настраиваем TYPE_RINGTONE

Далее мы вводим метод getCount для того, чтобы подсчитать количество доступных рингтонов и вызываем метод getRingtone в цикле for для того, чтобы добавить доступные звуки в ringtones

changeRingtone

Далее мы создаем метод changeRingtone, который будет ответственен за изменение рингтона на устройстве. Этот метод является ядром нашего приложения:

public static void changeRingtone(Context context){
 
 SharedPreferences preferences = context.getSharedPreferences("randomizer", Context.MODE_PRIVATE);
 if(!preferences.getBoolean("active", false))
 return;
 
 RingtoneManager mgr = new RingtoneManager(context);
 Random random = new Random(System.currentTimeMillis());
 
 int n = random.nextInt(mgr.getCursor().getCount()); 
 
 RingtoneManager.setActualDefaultRingtoneUri(context,
 RingtoneManager.TYPE_RINGTONE, mgr.getRingtoneUri(n));
}

В SharedPreferences мы проверяем, включил ли функцию случайного рингтона пользователь, активна ли она. Далее используется класс Random для выбора случайного числа, которое меньше чем количество доступных рингтонов. 

Метод getRingtoneUri вызывается для того, чтобы сделать выбор ссылки URI соответствующего рингтона и связать его с методом setActualDefaultRingtoneUri для смены проигрываемого звука. 

Теперь создаем новый класс RingReceiver, который наследуется от BroadcastReceiver. Новый класс будет иметь только один метод по имени onReceive. В этом методе мы в свою очередь вызываем метод changeRingtone, который нужен для взаимодействия с вспомогательным классом. 

public class RingReceiver extends BroadcastReceiver {
 
 @Override
 public void onReceive(Context context, Intent intent) {
 
 if(intent.getAction().equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
 String callState = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
 if (callState.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
 RingtoneHelper.changeRingtone(context);
 }
 }
 }
}

 

Теперь пришло время для создания основной Activity с именем MainActivity. Создаем ее и наследуем класс Activity. Создаем метод onCreate и выполняем следующие действия:

     - вызываем setContentView для использования разметки, определенной в activity_main.xml;

     - вызываем метод fetchAvailableRingtones для заполнения списка List рингтонов;

     - инициализируем ListView;

     - инициализируем ToggleButton;

Файл MainActivity.java должен выглядеть примерно следующим образом:

public class MainActivity extends Activity {
 
 private ListView listOfRingtones;
 private ToggleButton toggleRandomizer;
 private List<Ringtone> ringtones;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 
 setContentView(R.layout.activity_main);
 listOfRingtones = (ListView)findViewById(R.id.list_of_ringtones);
 toggleRandomizer = (ToggleButton)findViewById(R.id.toggle);
 
 ringtones = RingtoneHelper.fetchAvailableRingtones(this);
 initializeList();
 initializeToggle();
 }
}

initializeToggle

В методе initializeToggle происходит настройка ToggleButton в неактивное состояние ("false"). Также добавляем сюда OnCheckedChangeListener. Методы putBoolean и commit служат для обновления значения в ToggleButton

private void initializeToggle(){
 final SharedPreferences preferences = getSharedPreferences("randomizer", Context.MODE_PRIVATE);
 boolean active = preferences.getBoolean("active", false);
 toggleRandomizer.setChecked(active);
 
 toggleRandomizer.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
 @Override
 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
 preferences.edit().putBoolean("active", isChecked).commit();
 }
 });
}

initializeList

Метод initializeList создает Adapter, основанный на списке рингтонов. Для списка используем стандартный вид android.R.layout.simple_list_item_1.

Осталось поработать над нашим TextView. В нем должно отображаться название рингтона. Для этого используется метод getTitle. Это нужно выполнить внутри метода getView в Adapter, после его объявления. 

После завершения работы над Adapter, передаем его в ListView с помощью метода setAdapter:

private void initializeList(){
 ArrayAdapter<Ringtone> adapter = new ArrayAdapter<Ringtone>(this,
 android.R.layout.simple_list_item_1, ringtones) {
 @Override
 public View getView(int position, View convertView, ViewGroup parent) {
 TextView item = (TextView)super.getView(position, convertView, parent);
 item.setText(ringtones.get(position).getTitle(MainActivity.this));
 return item;
 }
 };
 
 listOfRingtones.setAdapter(adapter);
}

Все, наше приложение готово к установке! При запуске приложения вы должны увидеть все доступные на устройстве звуковые файлы. Жмем на ToggleButton для активации приложения и можем тестировать. Стоит отметить, что при первом входящем звонке будет проигрываться установленная на устройстве мелодия, при следующих звонках начнет действовать созданная программа. Приложение не будет работать, если на смартфоне на звонке установлена какая то сторонняя мелодия, оно может работать только с стандартными рингтонами

 Оригинал статьи здесь.

Категория: Уроки программирования | Просмотров: 928 | Добавил: Oleg | Теги: звонок, входящий вызов, Android приложение | Рейтинг: 0.0/0
Всего комментариев: 0
avatar