a. With example, explain the difference between Implicit and Explicit Intent.(2 Marks)
Answer (Click to show)
Explicit Intent: Specifies the exact component (activity, service, etc.) to start by name. Used within the same application.
Example:
Intent intent = new Intent(this, SecondActivity.class);startActivity(intent);
Implicit Intent: Declares an action to perform and lets another app handle it. Android system finds appropriate component to handle the intent.
Example:
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.google.com"));startActivity(intent);
b. Define a Splash Screen.(1 Mark)
Answer (Click to show)
A Splash Screen is a startup screen that appears while the application is loading. It displays a logo, brand name, or visual element to provide immediate feedback to users that the app is launching, improving user experience during initialization time.
c. Name the two permissions you need to declare in your AndroidManifest.xml file for sending and receiving SMS messages.(1 Mark)
Answer (Click to show)
android.permission.SEND_SMS
android.permission.RECEIVE_SMS
d. What is the difference between the onPause() method and the onSaveInstanceState() method?(1 Mark)
Answer (Click to show)
onPause() is called when the activity is partially visible and going into the background, used to pause operations like video playback or release system resources.
onSaveInstanceState() is called to save UI state data before the activity might be destroyed, storing temporary data in a Bundle to restore when the activity recreates.
QUESTION 2
Provide a brief description of the following android project resources:(1 Mark Each)
a. res/mipmap
Answer (Click to show)
The res/mipmap folder stores launcher icon files at different densities (mdpi, hdpi, xhdpi, etc.). These icons appear on the device’s home screen and in the app drawer. Mipmap folders ensure launcher icons scale properly across different devices.
b. Gradle
Answer (Click to show)
Gradle is an automated build system used in Android Studio. It manages project dependencies, compiles resources, runs tests, and packages the application into APK files. The build.gradle files contain configuration for build types, dependencies, SDK versions, and signing configurations.
c. res/drawable
Answer (Click to show)
The res/drawable folder contains image resources (PNG, JPG, GIF) and XML drawable files used in the application. This includes button backgrounds, shapes, selectors, and vector assets that define graphics displayed in the user interface.
d. Menu
Answer (Click to show)
Menu refers to XML files in the res/menu folder that define menu items for options menus, context menus, and action bar items. These files specify item IDs, titles, icons, and show/hide conditions for menu elements in the application.
e. Manifests/
Answer (Click to show)
The Manifests/ folder contains the AndroidManifest.xml file, which is the essential configuration file for every Android app. It declares app components (activities, services, receivers), required permissions, hardware/software features, and minimum API level requirements.
QUESTION 3
With examples, briefly provide the explanation of the following features:(1 Mark Each)
a. String.xml
Answer (Click to show)
String.xml is a resource file in res/values/ that stores all text strings used in the application. It enables localization and centralizes text management.
Example:
<resources> <string name="app_name">My Application</string> <string name="welcome_message">Welcome to the app!</string></resources>
b. Colors.xml
Answer (Click to show)
Colors.xml is a resource file in res/values/ that defines color constants used throughout the application for consistent theming.
Example:
Android Virtual Device (AVD) is an emulator configuration that simulates physical Android devices for testing applications. It defines device specifications like screen size, resolution, API level, and hardware features.
Example: Pixel 4 AVD with API 30, running Android 11, with 2GB RAM and 200MB internal storage.
d. TOAST
Answer (Click to show)
Toast is a popup message that appears briefly on the screen and automatically fades away without user interaction. It provides simple feedback without interrupting the current activity.
Example:
View is the basic building block for UI components in Android. It occupies a rectangular area on the screen and handles drawing and event handling. All UI widgets (Button, TextView, EditText) are subclasses of View.
Example: Button, TextView, ImageView are all types of Views.
SECTION B: (45 MARKS)
Attempt THREE (3) out of FOUR (4) questions in this section.
QUESTION 4
You have been asked by the management of Dodoma Secondary School to develop a mobile application that will store the information of the students. The app should store name, region, age, gender and subjects of the student. The management want to show the reports of how the student performs his/her subjects (English, Mathematics, Physics, Chemistry and Biology). The management also wants to show the dates of different events within the school. The management suggests the following features to be used: radio button for gender, spinner for region, and checkboxes for subjects. Use progress bar to show the performance of the students and calendar to show the dates of the events. Based on the given requirements, you found that the application has only two activities i.e. ActivityOne and ActivityTwo.
a. Using the methods of Intent class show how you will send the student’s data to the second activity.(3 Marks)
Answer (Click to show)
Sending data from ActivityOne to ActivityTwo using Intent:
// In ActivityOne.javaIntent intent = new Intent(ActivityOne.this, ActivityTwo.class);// Sending student data using putExtra() methodsintent.putExtra("student_name", studentName);intent.putExtra("student_region", selectedRegion);intent.putExtra("student_age", age);intent.putExtra("student_gender", selectedGender);// Sending array of subjects (checkboxes selected)String[] subjects = {"English", "Mathematics", "Physics", "Chemistry", "Biology"};intent.putExtra("student_subjects", subjects);// Using putExtras() with BundleBundle studentBundle = new Bundle();studentBundle.putString("name", studentName);studentBundle.putString("region", selectedRegion);studentBundle.putInt("age", Integer.parseInt(ageText));studentBundle.putString("gender", selectedGender);studentBundle.putStringArray("subjects", subjects);intent.putExtras(studentBundle);startActivity(intent);
b. Using the methods of Intent class show how you will receive the student’s data within the second activity.(3 Marks)
Answer (Click to show)
Receiving data in ActivityTwo from Intent:
// In ActivityTwo.java - onCreate() methodIntent receivedIntent = getIntent();// Retrieving individual extrasString studentName = receivedIntent.getStringExtra("student_name");String studentRegion = receivedIntent.getStringExtra("student_region");int studentAge = receivedIntent.getIntExtra("student_age", 0);String studentGender = receivedIntent.getStringExtra("student_gender");String[] studentSubjects = receivedIntent.getStringArrayExtra("student_subjects");// Retrieving from BundleBundle receivedBundle = receivedIntent.getExtras();if (receivedBundle != null) { String name = receivedBundle.getString("name"); String region = receivedBundle.getString("region"); int age = receivedBundle.getInt("age"); String gender = receivedBundle.getString("gender"); String[] subjects = receivedBundle.getStringArray("subjects"); // Display or process the received data textViewName.setText(name); textViewRegion.setText(region); textViewAge.setText(String.valueOf(age)); textViewGender.setText(gender);}
c. By the help of SQLiteOpenHelper class, show how you can save the student’s details in a database. Use user and student as the name of the database and table respectively.(9 Marks)
Answer (Click to show)
SQLiteOpenHelper implementation for student database:
// DatabaseHelper.java - SQLiteOpenHelper classimport android.content.ContentValues;import android.content.Context;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteOpenHelper;public class DatabaseHelper extends SQLiteOpenHelper { // Database and table names private static final String DATABASE_NAME = "user.db"; private static final String TABLE_NAME = "student"; private static final int DATABASE_VERSION = 1; // Column names private static final String COL_ID = "id"; private static final String COL_NAME = "name"; private static final String COL_REGION = "region"; private static final String COL_AGE = "age"; private static final String COL_GENDER = "gender"; private static final String COL_SUBJECTS = "subjects"; // Create table query private static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + "(" + COL_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + COL_NAME + " TEXT, " + COL_REGION + " TEXT, " + COL_AGE + " INTEGER, " + COL_GENDER + " TEXT, " + COL_SUBJECTS + " TEXT)"; public DatabaseHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { // Create the student table db.execSQL(CREATE_TABLE); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // Drop older table if exists and create new db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME); onCreate(db); } // Method to insert student data public long insertStudent(String name, String region, int age, String gender, String subjects) { SQLiteDatabase db = this.getWritableDatabase(); ContentValues contentValues = new ContentValues(); contentValues.put(COL_NAME, name); contentValues.put(COL_REGION, region); contentValues.put(COL_AGE, age); contentValues.put(COL_GENDER, gender); contentValues.put(COL_SUBJECTS, subjects); // Insert row and return the row ID long id = db.insert(TABLE_NAME, null, contentValues); db.close(); return id; } // Method to save all student details from ActivityOne public void saveStudentDetails(String name, String region, int age, String gender, String[] subjects) { // Convert subjects array to comma-separated string StringBuilder subjectsStr = new StringBuilder(); for (String subject : subjects) { subjectsStr.append(subject).append(","); } // Insert into database long result = insertStudent(name, region, age, gender, subjectsStr.toString()); if (result != -1) { // Successfully saved System.out.println("Student saved with ID: " + result); } else { // Failed to save System.out.println("Failed to save student"); } }}// Usage in ActivityOne or ActivityTwoDatabaseHelper dbHelper = new DatabaseHelper(this);dbHelper.saveStudentDetails("John Doe", "Dar es Salaam", 16, "Male", new String[]{"English", "Math", "Physics"});
QUESTION 5
The prime purpose of a content provider is to serve as a central repository of data where users can store and can fetch the data. The access of this repository is given to other applications also but in a safe manner in order to serve the different requirements of the user. Write an application that will allow users store their details such as name and phone numbers in a content provider. The application should also allow other applications to retrieve the stored user’s information. The application has one activity called MainActivity, two edit texts for name and phone number and two buttons for save data and view data. The ids for the views are etName, etPhoneNumber, btnSave and btnView.
(15 Marks)
Android Fragment represents a behavior or a portion of a user interface in an activity. Multiple fragments can be combined in a single activity to build a multi-panel User Interface (UI) and reuse a fragment in multiple activities. As a mobile apps developer, you have been asked to develop an application with two fragments named FragmentOne and FragmentTwo. When a user click on the specific fragment, the description of the fragment displays on the fragment container in the main activity which hosts the fragments. Assume the ids for FragmentOne and FragmentTwo are btnFragment_one and btnFragment_two respectively. Hint: use linear layout to create a fragment container.
(15 Marks)
Answer (Click to show)
Complete Fragment Implementation:
1. activity_main.xml - Main activity layout with fragment container
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="24dp" android:background="#E8E8E8"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="FRAGMENT ONE" android:textSize="24sp" android:textColor="#6200EE" android:textStyle="bold" android:gravity="center" android:layout_marginBottom="24dp"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="This is Fragment One description.\n\nFragment One represents the first portion of the user interface. It contains specific functionality and UI elements that are part of the main activity. Clicking on Fragment One button displays this description in the fragment container." android:textSize="16sp" android:lineSpacingExtra="4dp" android:padding="16dp" android:background="#FFFFFF" android:elevation="2dp"/> <ImageView android:layout_width="100dp" android:layout_height="100dp" android:layout_gravity="center_horizontal" android:layout_marginTop="32dp" android:src="@android:drawable/ic_dialog_info" android:contentDescription="Info Icon"/></LinearLayout>
3. fragment_two.xml - Layout for FragmentTwo
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="24dp" android:background="#E0F2F1"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="FRAGMENT TWO" android:textSize="24sp" android:textColor="#03DAC5" android:textStyle="bold" android:gravity="center" android:layout_marginBottom="24dp"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="This is Fragment Two description.\n\nFragment Two represents the second portion of the user interface. It contains different functionality and UI elements. Multiple fragments can be combined in a single activity to build multi-panel UIs and fragments can be reused in multiple activities." android:textSize="16sp" android:lineSpacingExtra="4dp" android:padding="16dp" android:background="#FFFFFF" android:elevation="2dp"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="32dp" android:text="Fragment Two Action" android:backgroundTint="#03DAC5"/></LinearLayout>
4. FragmentOne.java - First fragment class
import android.os.Bundle;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import androidx.fragment.app.Fragment;public class FragmentOne extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment return inflater.inflate(R.layout.fragment_one, container, false); } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); // Additional initialization after view is created }}
5. FragmentTwo.java - Second fragment class
import android.os.Bundle;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import androidx.fragment.app.Fragment;public class FragmentTwo extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment return inflater.inflate(R.layout.fragment_two, container, false); } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); // Additional initialization after view is created }}
6. MainActivity.java - Host activity with fragment management
import android.os.Bundle;import android.view.View;import android.widget.Button;import androidx.appcompat.app.AppCompatActivity;import androidx.fragment.app.Fragment;import androidx.fragment.app.FragmentManager;import androidx.fragment.app.FragmentTransaction;public class MainActivity extends AppCompatActivity { private Button btnFragmentOne, btnFragmentTwo; private FragmentManager fragmentManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btnFragmentOne = findViewById(R.id.btnFragment_one); btnFragmentTwo = findViewById(R.id.btnFragment_two); // Initialize FragmentManager fragmentManager = getSupportFragmentManager(); // Set default fragment (optional) if (savedInstanceState == null) { loadFragment(new FragmentOne()); } btnFragmentOne.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { loadFragment(new FragmentOne()); } }); btnFragmentTwo.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { loadFragment(new FragmentTwo()); } }); } private void loadFragment(Fragment fragment) { // Begin fragment transaction FragmentTransaction transaction = fragmentManager.beginTransaction(); // Replace the fragment in the container transaction.replace(R.id.fragment_container, fragment); // Add to back stack (optional - allows back navigation) transaction.addToBackStack(null); // Commit the transaction transaction.commit(); } // Handle back button to navigate through fragments @Override public void onBackPressed() { if (fragmentManager.getBackStackEntryCount() > 1) { fragmentManager.popBackStack(); } else { super.onBackPressed(); } }}
7. Alternative approach with FragmentTransaction methods (Bonus)
// Additional fragment transaction methodsprivate void loadFragmentWithAnimation(Fragment fragment) { FragmentTransaction transaction = fragmentManager.beginTransaction(); // Add custom animations transaction.setCustomAnimations( android.R.anim.fade_in, // enter android.R.anim.fade_out, // exit android.R.anim.slide_in_left, // popEnter android.R.anim.slide_out_right // popExit ); transaction.replace(R.id.fragment_container, fragment); transaction.addToBackStack(null); transaction.commit();}// Method to pass data to fragmentsprivate void loadFragmentWithData(Fragment fragment, Bundle data) { fragment.setArguments(data); loadFragment(fragment);}
QUESTION 7
(a) There are tasks that do not really need to be visible to the user. A good example is playing a music. You don’t need to keep the player’s screen for song to play. Those kinds of applications/tasks runs in the background.
i. Suggests the kind of android component that you can use to accomplish such kind of task.(2 Marks)
Answer (Click to show)
The appropriate Android component for background tasks like playing music is a Service, specifically a Foreground Service.
Service: A component that runs in the background to perform long-running operations without a user interface.
Foreground Service: A service that shows a persistent notification to the user, indicating that the app is performing a task (like playing music). This has higher priority and is less likely to be killed by the system.
For music playback, the recommended approach is using MediaBrowserService or MediaSession with a Foreground Service, which properly integrates with Android’s audio framework and maintains playback even when the app is not visible.
ii. Based on your suggestion in part (i), write a java class to implement a task for playing music. Assume the music you want to play is located at Settings.System.DEFAULT_RINGTONE_URI(7 Marks)
Answer (Click to show)
Complete Music Playing Service Implementation:
import android.app.Notification;import android.app.NotificationChannel;import android.app.NotificationManager;import android.app.PendingIntent;import android.app.Service;import android.content.Intent;import android.media.MediaPlayer;import android.net.Uri;import android.os.Build;import android.os.IBinder;import android.provider.Settings;import androidx.core.app.NotificationCompat;public class MusicPlaybackService extends Service { private static final String CHANNEL_ID = "MusicPlaybackChannel"; private static final int NOTIFICATION_ID = 1; private MediaPlayer mediaPlayer; private boolean isPlaying = false; @Override public void onCreate() { super.onCreate(); createNotificationChannel(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // Start as foreground service with notification startForeground(NOTIFICATION_ID, createNotification()); // Initialize and start music playback startMusicPlayback(); // Return START_STICKY to ensure service restarts if killed return START_STICKY; } private void startMusicPlayback() { try { // Get default ringtone URI (as specified in the question) Uri ringtoneUri = Settings.System.DEFAULT_RINGTONE_URI; // Initialize MediaPlayer mediaPlayer = MediaPlayer.create(this, ringtoneUri); // Set loop to true for continuous playback mediaPlayer.setLooping(true); // Set volume mediaPlayer.setVolume(0.5f, 0.5f); // Set completion listener mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { // Handle completion if not looping stopSelf(); } }); // Set error listener mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() { @Override public boolean onError(MediaPlayer mp, int what, int extra) { // Handle errors stopSelf(); return false; } }); // Start playback mediaPlayer.start(); isPlaying = true; } catch (Exception e) { e.printStackTrace(); stopSelf(); } } private Notification createNotification() { // Create intent to launch activity when notification is clicked Intent notificationIntent = new Intent(this, MainActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE); // Create play/pause action Intent playPauseIntent = new Intent(this, MusicPlaybackService.class); playPauseIntent.setAction("PLAY_PAUSE"); PendingIntent playPausePendingIntent = PendingIntent.getService(this, 1, playPauseIntent, PendingIntent.FLAG_IMMUTABLE); // Create stop action Intent stopIntent = new Intent(this, MusicPlaybackService.class); stopIntent.setAction("STOP"); PendingIntent stopPendingIntent = PendingIntent.getService(this, 2, stopIntent, PendingIntent.FLAG_IMMUTABLE); // Build notification NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID) .setContentTitle("Music Player") .setContentText("Playing default ringtone") .setSmallIcon(android.R.drawable.ic_media_play) .setContentIntent(pendingIntent) .setPriority(NotificationCompat.PRIORITY_LOW) .setOngoing(true) // Makes notification non-dismissible .addAction(android.R.drawable.ic_media_pause, "Pause", playPausePendingIntent) .addAction(android.R.drawable.ic_menu_close_clear_cancel, "Stop", stopPendingIntent); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { builder.setChannelId(CHANNEL_ID); } return builder.build(); } private void createNotificationChannel() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel( CHANNEL_ID, "Music Playback Service", NotificationManager.IMPORTANCE_LOW ); channel.setDescription("Channel for music playback service"); NotificationManager manager = getSystemService(NotificationManager.class); manager.createNotificationChannel(channel); } } @Override public IBinder onBind(Intent intent) { return null; // This service doesn't support binding } @Override public void onDestroy() { super.onDestroy(); // Clean up resources if (mediaPlayer != null) { if (mediaPlayer.isPlaying()) { mediaPlayer.stop(); } mediaPlayer.release(); mediaPlayer = null; } isPlaying = false; } // Method to handle actions from notification private void handleAction(String action) { switch (action) { case "PLAY_PAUSE": if (isPlaying) { mediaPlayer.pause(); isPlaying = false; updateNotificationPlayPauseIcon(false); } else { mediaPlayer.start(); isPlaying = true; updateNotificationPlayPauseIcon(true); } break; case "STOP": stopSelf(); break; } } private void updateNotificationPlayPauseIcon(boolean isPlaying) { // Update notification with new icon Notification notification = createNotification(); NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); manager.notify(NOTIFICATION_ID, notification); }}
(b) The management of CIVE cafeteria wants to implement an android system that will manage its customers. The application has only one activity named MainActivity with three edit texts and one button. One of the functionality of the application is to store the customer’s information such as name, email and phone number. The customer’s data are in small amount and are in key/value pairs. Write an android application that will store the customer’s information in a Shared Preference. The ids for the edit texts and button are etName, etEmail, etPhoneNumber and btnSave.
(6 Marks)
Answer (Click to show)
Complete SharedPreferences Implementation for Customer Management: