5COSC005W - Tutorial 9 Exercises

As part of this tutorial for this week, you should complete ALL the tasks described in the following links and specifications: (make sure that you ask questions to your tutor for anything that you do not understand or if you are stuck at any point):

1 Options Menus

a) Implement an Android application which contains an actions overflow menu with two entries: Settings and Options2 which when selected they create a pop up Toast with their name:

tutorial9a.png

b) Add a Favourites icon in the main app bar options menu (not the overflow menu) which is always displayed and when clicked in displays a toast message:

tutorial9b.png

2 Contextual Menus

Extend the application so that it contains a textview with a contectual menu containing 2 entries Edit and Share:

tutorial9c.png

Choosing option Edit should display a dialog with 2 options:

tutorial9d.png

Choosing option Share should send some random text to an application that the user can choose from (hint: use an impliciti intend with an ACTIONSEND).

tutorial9e.png

3 Contextual Action Bars

Modify the application so that the textview created uses a contextual action bar instead displaying an edit icon which when selected it displays the same dialog to the user as the one displayed with the Edit entry above in the implementation of contextual menus:

tutorial9f.png

4 Popup Menus

Add an ImageView in your application so that displays one of the images which are included with the assets of Android studio as in the image above. The image view should be associated with a popup window displaying 2 user options Forwards and ReplyAll (they do not need to do anything once chosen):

tutorial9g.png

5 The DatePicker

Add a button to the application so that when it is clicked it displays a DatePickerDialog.

tutorial9h.png

When the user clicks on the OK button a Toast is displayed with the selected date in the format day/month/year, e.g. 14/3/2021:

tutorial9i.png

6 The TimePicker

Add a button so that the application displays a TimePickerDialog when it is clicked. Once the user picks up a time, a toast with the time is displayed.

7 Solutions

The main activity MainActivity.java:

package uk.ac.westminster.menustest;

import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;

import android.util.Log;
import android.view.ActionMode;
import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageButton;
import android.widget.PopupMenu;
import android.widget.TextView;
import android.widget.Toast;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.DialogFragment;

public class MainActivity extends AppCompatActivity {
    TextView tv;
    ImageButton bt1;
    ActionMode mActionMode;
    android.view.ActionMode.Callback mActionModeCallback;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        mActionModeCallback = new ActionMode.Callback() {
            @Override
            public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
                actionMode.getMenuInflater().inflate(R.menu.menu_context_bar, menu);

                return true;
            }

            @Override
            public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
                return false;
            }

            @Override
            public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
                switch (menuItem.getItemId()) {
                    case R.id.edit_option:
                        editNote();
                        actionMode.finish();
                        return true;
                    default:
                        return false;
                }
            }

            @Override
            public void onDestroyActionMode(ActionMode actionMode) {
                mActionMode = null;
            }
        };

        tv = findViewById(R.id.tv);
        registerForContextMenu(tv);

        bt1 = findViewById(R.id.button_popup);
        bt1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                PopupMenu pop = new PopupMenu(MainActivity.this, bt1);
                pop.getMenuInflater().inflate(R.menu.menu_popup, pop.getMenu());
                pop.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
                    @Override
                    public boolean onMenuItemClick(MenuItem menuItem) {
                        switch (menuItem.getItemId()) {
                            case R.id.forward:
                                return true;
                            default:
                                return false;
                        }
                    }
                });
                pop.show();
            }
        });


        /***  Comment out this segment of code to use a contextual menu instead of the
         *    contectual action bar *****/
        tv.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View view) {
                if (mActionMode != null)
                    return false;
                else {
                    MainActivity.this.startActionMode(mActionModeCallback);

                    return true;
                }
            }
        });   /*** segment of code for contextual action bar ends here ***/

    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);

        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;

    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.option_favourites:
                showFavourites();
                return true;
            case R.id.option_settings:
                showSettings();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }


    void showFavourites() {
        Toast t = Toast.makeText(this, "Favourites shown", Toast.LENGTH_SHORT);
        t.show();
    }

    void showSettings() {
        Toast t = Toast.makeText(this, "Settings shown", Toast.LENGTH_SHORT);
        t.show();
    }

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);

        getMenuInflater().inflate(R.menu.menu_context, menu);

    }

    @Override
    public boolean onContextItemSelected(MenuItem item) {
        if (item.getItemId() == R.id.context_edit) {
            editNote();
            return true;
        } else if (item.getItemId() == R.id.context_share) {
            shareNote();
            return true;
        } else
            return super.onContextItemSelected(item);
    }

    void editNote() {
        AlertDialog.Builder dialog = new AlertDialog.Builder(this);
        dialog.setTitle("Edit choice22727");
        dialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {

            }
        });
        dialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {

            }
        });
        dialog.show();
    }

    void shareNote() {
        Intent i = new Intent(Intent.ACTION_SEND);
        i.setType("text/plain");
        i.putExtra(Intent.EXTRA_TEXT, "gsutytygsg");
        i = Intent.createChooser(i, "Report from app");
        startActivity(i);
    }

    public void onDateClick(View view) {
        DialogFragment df = new DatePickerFragment();
        df.show(getSupportFragmentManager(), "datepicker");
    }

    public void showSomething(int year, int month, int day) {
        Toast t = Toast.makeText(this, "" + day + "/" + month + "/" + year, Toast.LENGTH_SHORT);
        t.show();
    }
}

The layout file activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="24sp"
        android:layout_gravity="center"
        android:text="TextView with a Contextual menu" />

    <ImageButton
        android:id="@+id/button_popup"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:src="@drawable/ic_action_popup" />
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="Click me"
        android:textSize="24sp"
        android:onClick="onDateClick"/>
</LinearLayout>

The menu files are below (they need to be placed under the res/menu/ directory.

The menu_main.xml file:

<?xml version="1.0" encoding="utf-8"?>
<menu
      xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto" >
    <item android:id="@+id/option2"
        android:title="Option2"
        android:orderInCategory="90"/>
    <item android:id="@+id/option_settings"
        android:title="Settings"
        android:orderInCategory="60"
        android:icon="@drawable/ic_action_settings"/>
    <item android:id="@+id/option_favourites"
        android:title="Favourites"
        app:showAsAction="ifRoom"
        android:icon="@drawable/ic_favourites"
        android:orderInCategory="30"
        />
</menu>

The menu_context file:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/context_edit"
        android:title="Edit"/>
    <item android:id="@+id/context_share"
        android:title="Share" />
</menu>

The menu_context_bar.xml file:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:id="@+id/edit_option"
        android:title="Edit"
        android:icon="@drawable/ic_action_edit"/>
</menu>

The menu_popup.xml file:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/forward"
        android:title="Forwards" />
    <item android:id="@+id/replyall"
        android:title="ReplyAll"/>
</menu>

The DatePickerFragment.java file:

package uk.ac.westminster.menustest;


import android.app.DatePickerDialog;
import android.app.Dialog;
import android.os.Bundle;

import android.widget.DatePicker;

import androidx.annotation.NonNull;
import androidx.fragment.app.DialogFragment;

/**
 * A simple  Fragment subclass.
 */
public class DatePickerFragment extends DialogFragment implements DatePickerDialog.OnDateSetListener {
    @NonNull
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        return new DatePickerDialog(getActivity(), this, 2019, 2, 14);
    }

    @Override
    public void onDateSet(DatePicker datePicker, int i, int i1, int i2) {
        MainActivity activity = (MainActivity) getActivity();
        activity.showSomething(i, i1, i2);
    }
}

8 Dealing with a TimePicker

Extend the application so that at the bottom it displays an additional buton called Time. The button is associated with a TimePickerDialog. When the user selects a time in the dialog, the selected time is displayed in a TextView at the bottom of the main activity.

9 Adding new Items in the Options menu.

Extend the application so that it displays an additional menu item (choose an icon of your choice) next to the "Favourites" item. When the item is clicked, it should open a browser displaying your favourite URL. (Hint: use an implicit intent, something we covered in Week 3).

10 Persisting Settings in an Application

Modify the application so that the Settings option found in the overflow menu displays a date dialog picker which then user can use to select the date of the birthday of his/her best friend. The date should be persisted as part of the application settings (use SharedPreferences) so that the next time that the application restarts the birthday of the user's best friend is displayed.