0

I'm beginner for Android Studio I try to make the Android Alarm Clock and now it cannot display the notifications, no music has played and also there is the error for the stop button. This is my code, wish someone can help me to solve it. Thank you

AlarmReceiver.java

package com.google.alarmclock;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

public class Alarm_Receiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent)
{
    Log.e("We are in the Receiver","yaa");

    //fetch extra strings from the intent
    String get_your_string = intent.getExtras().getString("extra");

    Log.e("What is the key?", get_your_string);

    //create an intent to the ringtone service
    Intent service_intent=new Intent(context,RingtonePlayingService.class);

    //pass the extra string from Main Activity to the Ringtone Playing Service,pass to the start service
    service_intent.putExtra("extra",get_your_string);

    //start the ringtone service
    context.startService(service_intent);
}
}

MainActivity.java

package com.google.alarmclock;

import android.annotation.TargetApi;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Button;
import android.widget.TextView;
import android.widget.TimePicker;
import java.util.Calendar;

public class MainActivity extends AppCompatActivity {
//to make alarm manager
AlarmManager alarm_manager;
TimePicker alarm_timepicker;
TextView update_text;
Context context;
PendingIntent pending_intent;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);
    this.context = this;

    //initialize alarm manager
    alarm_manager=(AlarmManager)getSystemService(ALARM_SERVICE);

    //initialize timepicker
    alarm_timepicker=(TimePicker)findViewById(R.id.timePicker);

    //initialize our text update box
    update_text=(TextView)findViewById(R.id.update_text);

    //create an instance of a calender
    final Calendar calendar= Calendar.getInstance();

    //create an intent to the Alarm Receiver class
    final Intent my_intent=new Intent(MainActivity.this,Alarm_Receiver.class);

    //initialize start buttons
    Button alarm_on=(Button)findViewById(R.id.start_alarm);
    //create an onClick listener to start the alarm
    alarm_on.setOnClickListener(new View.OnClickListener() {
        @TargetApi(Build.VERSION_CODES.M)
        @Override
        public void onClick(View view) {

            //setting calendar instance with the hour and minute that ve picked
            //on the time picker
            calendar.set(Calendar.HOUR_OF_DAY,alarm_timepicker.getCurrentHour());
            calendar.set(Calendar.MINUTE,alarm_timepicker.getCurrentMinute());

            //get the string values of the hour and minute
            int hour=alarm_timepicker.getCurrentHour();
            int minute=alarm_timepicker.getCurrentMinute();

            //converts the int value to strings
            String hour_string=String.valueOf(hour);
            String minute_string=String.valueOf(minute);

            //conver 24hour time to 12 hour time
            if(hour>12)
            {
                hour_string=String.valueOf(hour-12);
            }

            if(minute<10){
                minute_string="0" +String.valueOf(minute);
            }

            //method that changes the update text Textbox
            set_alarm_text("Alarm set to: "+hour_string+ ":" + minute_string);

            //put in extra string into my_intent
            //tells the clock that you pressed the "alarm on" button
            my_intent.putExtra("extra","alarm on");

            //create a pending intent that delays the intent
            //until the specified calendar time
            pending_intent=PendingIntent.getBroadcast(MainActivity.this,0,my_intent,PendingIntent.FLAG_UPDATE_CURRENT);

            //set the alarm manager
            alarm_manager.set(AlarmManager.RTC_WAKEUP,calendar.getTimeInMillis(),pending_intent);
        }
    });

    //initialize the stop button
    Button alarm_off=(Button)findViewById(R.id.end_alarm);
    //create an onClick listener to undo an alarm set
    alarm_off.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            //method that changes the update text Textbox
            set_alarm_text("Alarm off!");

            //cancel the alarm
            alarm_manager.cancel(pending_intent);

            //put extra string into my_intent
            //tells the clock that you pressed the "alarm off" button
            my_intent.putExtra("extra","alarm off");


            //stop the ringtone
            sendBroadcast(my_intent);
        }
    });
}

private void set_alarm_text(String output) {
    update_text.setText(output);

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        return true;
    }

    return super.onOptionsItemSelected(item);
}
}

RingtonePlayingService.java

  package com.google.alarmclock;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;
import android.widget.Toast;

import java.security.Provider;
import java.util.List;
import java.util.Map;


public class RingtonePlayingService extends Service {

MediaPlayer player=MediaPlayer.create(this, Settings.System.DEFAULT_RINGTONE_URI);
int startId;
boolean isRunning;

@Nullable
@Override
public IBinder onBind(Intent intent) {
    return null;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

    Log.i("LocalService", "Received start id " + startId + ": " + intent);

    //fetch the extra string values
    String state = intent.getExtras().getString("extra");

    Log.e("Ringtone extra is",state);




    //this converts the extra strings from the intent
    //to start IDs, values 0 or 1
    assert state !=null;
    switch (state) {
        case "alarm on":
            startId = 1;
            break;
        case "alarm off":
            startId = 0;
            Log.e("Start ID is ",state);
            break;
        default:
            startId = 0;
            break;
    }


    //if else statements

    //if there is no music playing, and the user pressed "alarm on"
    //music should start playing
    if (!this.isRunning && startId==1)
    {
        Log.e("there is no music, ","and you want start");
        //create an instance of the media player
        player = MediaPlayer.create(this,R.raw.singer);
        player.start();

        this.isRunning=true;
        this.startId=0;

        //put the notification here,test it out
        //notification
        //set up the notification service
        NotificationManager notify_manager=(NotificationManager)
                getSystemService(NOTIFICATION_SERVICE);
        //set up an intent that goes to the Main Activity
        Intent intent_main_activity=new Intent(this.getApplicationContext(),MainActivity.class);

        //set up a pending intent
        PendingIntent pending_intent_main_activity=PendingIntent.getActivity(this,0,
                intent_main_activity,0);

        //make the notification parameters
       Notification notification_popup=new Notification.Builder(this)
                .setContentTitle("An alarm is going off!")
                .setContentText("Click Me")
                .setContentIntent(pending_intent_main_activity)
                .setAutoCancel(true)
                .setSmallIcon(R.mipmap.ic_launcher)
                .build();

        //set up the notification call command
        notify_manager.notify(0,notification_popup);

    }
    //if there is music playing, and the user pressed "alarm off"
    //music should stop playing
    else if (this.isRunning && startId == 0)
    {
        Log.e("there is music, ","and you want end");

        //stop the ringtone
        player.stop();
        player.reset();

        this.isRunning=false;
        this.startId=0;

    }
    //there are if user presses random buttons
    //just to bug-proof the app
    //if there is no music playing, and the user pressed "alarm off"
    //do nothing
    else if (!this.isRunning && startId == 0)
    {
        Log.e("there is no music, ","and you want end");

        //stop the ringtone
        this.isRunning=false;
        this.startId=0;

    }
    //if there is music playing and the user pressed "alarm on"
    //do nothing
    else if (this.isRunning && startId ==1)
    {
        Log.e("there is music, ","and you want start");

        this.isRunning =true;
        this.startId=1;

    }
    //can't think of anything else, just to catch the odd event
    else
    {
        Log.e("else ","somehow you reached ");

    }
    //if something is wrong, it can restart
    return START_NOT_STICKY;
}

@Override
public void onDestroy() {
    // Tell the user we stopped.
    Log.e("on Destroy called","ta da");
    super.onDestroy();
    this.isRunning=false;
    //Toast.makeText(this, "on Destroy called ", Toast.LENGTH_SHORT).show();
}

}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:theme="@style/AppTheme.NoActionBar">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

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

    <receiver android:name=".Alarm_Receiver"/>
    <service android:name=".RingtonePlayingService"
        android:enabled="true"/>
</application>

build.gradle

apply plugin: 'com.android.application'

android {
    compileSdkVersion 24
    buildToolsVersion "24.0.2"
    defaultConfig {
        applicationId "com.google.alarmclock"
        minSdkVersion 16
        targetSdkVersion 24
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:24.2.1'
    compile 'com.android.support:design:24.2.1'
    testCompile 'junit:junit:4.12'
}

this is the error when clicking the start button

Is this an error for the music?

java.lang.RuntimeException: Unable to start service com.google.alarmclock.RingtonePlayingService@1cba53b with Intent { cmp=com.google.alarmclock/.RingtonePlayingService (has extras) }: java.lang.IllegalArgumentException: Invalid notification (no valid small icon): Notification(pri=0 contentView=null vibrate=null sound=null defaults=0x0 flags=0x10 color=0x00000000 vis=PRIVATE)
                  at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3314)
                  at android.app.ActivityThread.-wrap21(ActivityThread.java)
                  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1565)
                  at android.os.Handler.dispatchMessage(Handler.java:102)
                  at android.os.Looper.loop(Looper.java:154)
                  at android.app.ActivityThread.main(ActivityThread.java:6077)
                  at java.lang.reflect.Method.invoke(Native Method)
                  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
                  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
               Caused by: java.lang.IllegalArgumentException: Invalid notification (no valid small icon): Notification(pri=0 contentView=null vibrate=null sound=null defaults=0x0 flags=0x10 color=0x00000000 vis=PRIVATE)
                  at android.app.NotificationManager.notifyAsUser(NotificationManager.java:306)
                  at android.app.NotificationManager.notify(NotificationManager.java:284)
                  at android.app.NotificationManager.notify(NotificationManager.java:268)
                  at com.google.alarmclock.RingtonePlayingService.onStartCommand(RingtonePlayingService.java:96)
                  at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3297)
                  at android.app.ActivityThread.-wrap21(ActivityThread.java) 
                  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1565) 
                  at android.os.Handler.dispatchMessage(Handler.java:102) 
                  at android.os.Looper.loop(Looper.java:154) 
                  at android.app.ActivityThread.main(ActivityThread.java:6077) 
                  at java.lang.reflect.Method.invoke(Native Method) 
                  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865) 
                  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755) 

When Click the stop button

E/AndroidRuntime: FATAL EXCEPTION: main
                  Process: com.google.alarmclock, PID: 2665
                  java.lang.NullPointerException: cancel() called with a null PendingIntent
                      at android.app.AlarmManager.cancel(AlarmManager.java:890)
                      at com.google.alarmclock.MainActivity$2.onClick(MainActivity.java:111)
                      at android.view.View.performClick(View.java:5609)
                      at android.view.View$PerformClick.run(View.java:22259)
                      at android.os.Handler.handleCallback(Handler.java:751)
                      at android.os.Handler.dispatchMessage(Handler.java:95)
                      at android.os.Looper.loop(Looper.java:154)
                      at android.app.ActivityThread.main(ActivityThread.java:6077)
                      at java.lang.reflect.Method.invoke(Native Method)
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
Jane
  • 71
  • 3
  • 7

1 Answers1

0

From your build.gradle I can see why the noSuchMethod exception is thrown. In order to use the function alarm_timepicker.getHour(). You must be targeting a min API of 23, in order to use this function without any problem.

The annotation you have wrapped your function in does not really do much. It just prevents warnings/errors to be displayed during the coding process. When the application is live the runtime exception will be thrown since the method cannot be found.

If you desire to keep using timepicker.getHour() make sure you specify in your build.gradle minSdkVersion 23. Note that this will require you to install your app onto a device running SDK 23.

If you don't want to make such modification to the build.gradle then I suggest you use this function. timepicker.getCurrentHour() and timepicker.getCurrentMinute().

In order to fix problem #2 related to java.lang.RuntimeException: Unable to start service com.google.alarmclock.RingtonePlayingService@1cba53b with Intent { cmp=com.google.alarmclock/.RingtonePlayingService (has extras) }: java.lang.IllegalArgumentException: Invalid notification (no valid small icon)

Make sure you set a small icon to your notification. A Notification Object requires that you set this property.

Try this:

Notification notification_popup=new Notification.Builder(this)
                    .setContentTitle("An alarm is going off!")
                    .setContentText("Click Me")
                    .setContentIntent(pending_intent_main_activity)
                    .setAutoCancel(true)
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .build();

Make sure you pay attention to the .setSmallIcon piece of code. Your project may not have the mipmap folder. You might have to change to R.drawable.ic_launcher

Related to the sound. I can't really tell if this is an issue yet I will update soon.

Thanks.

TerNovi
  • 390
  • 5
  • 16