Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,10 @@ captures/
# External native build folder generated in Android Studio 2.2 and later
.externalNativeBuild

# Google Services (e.g. APIs or Firebase)
# PNS Credentials
google-services.json
api_key.txt


# Freeline
freeline.py
Expand Down
20 changes: 20 additions & 0 deletions notification-hubs-sample-app-java/adm/debug/output-metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"version": 3,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "com.example.notification_hubs_sample_app_java.adm",
"variantName": "admDebug",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 1,
"versionName": "1.0",
"outputFile": "notification-hubs-sample-app-java-adm-debug.apk"
}
],
"elementType": "File"
}
32 changes: 30 additions & 2 deletions notification-hubs-sample-app-java/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ if (secretsPropertiesFile.exists()) {
secretsProperties.load(new FileInputStream(secretsPropertiesFile))
}

boolean USE_GOOGLE_SERVICES

android {
compileSdkVersion 31
buildToolsVersion "30.0.3"
Expand All @@ -29,14 +31,29 @@ android {
fcm {
dimension "push-provider"
applicationIdSuffix ".fcm"
USE_GOOGLE_SERVICES = true
}

general {
dimension "push-provider"
USE_GOOGLE_SERVICES = true
}

adm {
dimension "push-provider"
applicationIdSuffix ".adm"
USE_GOOGLE_SERVICES = false
}
}

signingConfigs {
debug {
storeFile file(System.getenv("ANH_SAMPLE_KEYSTORE_PATH"))
storePassword System.getenv("ANH_SAMPLE_KEYSTORE_PASSWORD")
keyAlias System.getenv("ANH_SAMPLE_KEY_NAME")
keyPassword System.getenv("ANH_SAMPLE_KEY_PASSWORD")
}

releaseSigningConfig {
storeFile rootProject.file("notification-hubs-sample-app-java/notification-hubs-sample-app.jks")
storePassword System.getProperty("APPCENTER_KEYSTORE_PASSWORD")
Expand All @@ -56,6 +73,13 @@ android {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
sourceSets {
adm {
assets {
srcDirs 'src\\adm\\assets'
}
}
}
}

dependencies {
Expand All @@ -64,13 +88,17 @@ dependencies {
implementation project(':notification-hubs-sdk')
implementation 'androidx.appcompat:appcompat:1.4.0'
implementation 'com.google.android.material:material:1.4.0'
implementation 'com.google.android.gms:play-services-base:17.6.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.2'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'

fcmImplementation 'com.google.android.gms:play-services-base:17.6.0'

testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}

apply plugin: 'com.google.gms.google-services'
if(USE_GOOGLE_SERVICES) {
apply plugin: 'com.google.gms.google-services'
}
16 changes: 16 additions & 0 deletions notification-hubs-sample-app-java/src/adm/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.notification_hubs_sample_app_java">

<application>
<receiver android:name="com.microsoft.windowsazure.messaging.notificationhubs.AnhAdmMessageReceiver"
android:permission="com.amazon.device.messaging.permission.SEND"
android:exported="true">
<intent-filter>
<action android:name="com.amazon.device.messaging.intent.REGISTRATION" />
<action android:name="com.amazon.device.messaging.intent.RECEIVE" />
<category android:name="com.example.notification_hubs_sample_app_java.adm" />
</intent-filter>
</receiver>
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package com.example.notification_hubs_sample_app_java.ui.main;

import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.example.notification_hubs_sample_app_java.R;

import java.util.ArrayList;
import java.util.List;

public class NotificationDisplayAdapter extends RecyclerView.Adapter<NotificationDisplayAdapter.ViewHolder> {

private List<Intent> mNotifications;
private NotificationClickListener mClickListener;
private final String mDefaultTitle;
private final String mDefaultMessage;

public NotificationDisplayAdapter(String defaultTitle, String defaultMessage) {
this(defaultTitle, defaultMessage, new ArrayList<Intent>(0));
}

public NotificationDisplayAdapter(String defaultTitle, String defaultMessage, List<Intent> initialList) {
mNotifications = initialList;
mClickListener = message -> {
// Intentionally Left Blank
};
mDefaultTitle = defaultTitle;
mDefaultMessage = defaultMessage;
}

/**
* Called when RecyclerView needs a new {@link ViewHolder} of the given type to represent
* an item.
* <p>
* This new ViewHolder should be constructed with a new View that can represent the items
* of the given type. You can either create a new View manually or inflate it from an XML
* layout file.
* <p>
* The new ViewHolder will be used to display items of the adapter using
* {@link #onBindViewHolder(ViewHolder, int, List)}. Since it will be re-used to display
* different items in the data set, it is a good idea to cache references to sub views of
* the View to avoid unnecessary {@link View#findViewById(int)} calls.
*
* @param parent The ViewGroup into which the new View will be added after it is bound to
* an adapter position.
* @param viewType The view type of the new View.
* @return A new ViewHolder that holds a View of the given view type.
* @see #getItemViewType(int)
* @see #onBindViewHolder(ViewHolder, int)
*/
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.notification_list_item, parent, false);
return new ViewHolder(v);
}

public void setNotifications(List<Intent> notifications) {
mNotifications = notifications;
notifyDataSetChanged();
}

public void setClickListener(NotificationClickListener listener) {
mClickListener = listener;
}

/**
* Called by RecyclerView to display the data at the specified position. This method should
* update the contents of the {@link ViewHolder#itemView} to reflect the item at the given
* position.
* <p>
* Note that unlike {@link ListView}, RecyclerView will not call this method
* again if the position of the item changes in the data set unless the item itself is
* invalidated or the new position cannot be determined. For this reason, you should only
* use the <code>position</code> parameter while acquiring the related data item inside
* this method and should not keep a copy of it. If you need the position of an item later
* on (e.g. in a click listener), use {@link ViewHolder#getAdapterPosition()} which will
* have the updated adapter position.
* <p>
* Override {@link #onBindViewHolder(ViewHolder, int, List)} instead if Adapter can
* handle efficient partial bind.
*
* @param holder The ViewHolder which should be updated to represent the contents of the
* item at the given position in the data set.
* @param position The position of the item within the adapter's data set.
*/
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Intent entry = mNotifications.get(position);

holder.mTitle.setText("Title Place Holder");
holder.mBody.setText("Body Place Holder");

holder.mDataCardinality.setText(String.valueOf(entry.getExtras().size()));
}

/**
* Returns the total number of items in the data set held by the adapter.
*
* @return The total number of items in this adapter.
*/
@Override
public int getItemCount() {
return mNotifications.size();
}

public class ViewHolder extends RecyclerView.ViewHolder {
private final TextView mTitle;
private final TextView mBody;
private final TextView mDataCardinality;

public ViewHolder(@NonNull View itemView) {
super(itemView);
mTitle = (TextView) itemView.findViewById(R.id.titleValue);
mBody = (TextView) itemView.findViewById(R.id.bodyValue);
mDataCardinality = (TextView) itemView.findViewById(R.id.dataCardinalityValue);
itemView.setOnClickListener(v -> {
Intent clicked = NotificationDisplayAdapter.this.mNotifications.get(getAdapterPosition());
NotificationDisplayAdapter.this.mClickListener.onNotificationClicked(clicked);
});
}
}

public interface NotificationClickListener {
void onNotificationClicked(Intent message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package com.example.notification_hubs_sample_app_java.ui.main;

import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;

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

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;


import com.example.notification_hubs_sample_app_java.NotificationDetailActivity;
import com.example.notification_hubs_sample_app_java.R;

import java.util.List;
import java.util.Map;

public class NotificationListFragment extends Fragment {

private NotificationListViewModel mViewModel;

public static NotificationListFragment newInstance() {
return new NotificationListFragment();
}

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mViewModel = new ViewModelProvider(this).get(NotificationListViewModel.class);
}

@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.notification_list_fragment, container, false);

final NotificationDisplayAdapter notificationDisplayAdapter = new NotificationDisplayAdapter(
this.getString(R.string.notification_untitled),
this.getString(R.string.notification_no_body));
final Observer<List<Intent>> notificationsObserver = notificationMessages -> {
notificationDisplayAdapter.setNotifications(notificationMessages);
Toast.makeText(this.getContext(), R.string.notification_received_message, Toast.LENGTH_SHORT).show();
};
mViewModel.getNotificationList().observe(getViewLifecycleOwner(), notificationsObserver);
final RecyclerView notificationList = root.findViewById(R.id.notificationList);
notificationList.setLayoutManager(new LinearLayoutManager(getActivity()));
notificationList.setAdapter(notificationDisplayAdapter);

notificationDisplayAdapter.setClickListener(message -> {
Intent i = new Intent(this.getActivity(), NotificationDetailActivity.class);
// i.putExtra(NotificationDetailActivity.INTENT_TITLE_KEY, "Title Place Holder");
// i.putExtra(NotificationDetailActivity.INTENT_BODY_KEY, "Body Place Holder");

i.putExtras(message.getExtras());
Bundle originalExtras = message.getExtras();
startActivity(i);
});

return root;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.example.notification_hubs_sample_app_java.ui.main;

import android.app.Notification;
import android.content.Intent;

import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

import com.microsoft.windowsazure.messaging.notificationhubs.NotificationHub;
import com.microsoft.windowsazure.messaging.notificationhubs.NotificationListener;

import java.util.ArrayList;
import java.util.List;

public class NotificationListViewModel extends ViewModel {
private final MutableLiveData<List<Intent>> mNotifications;
private final NotificationListener mListener;

public NotificationListViewModel() {
mNotifications = new MutableLiveData<List<Intent>>();
mListener = (context, message) -> {
addNotification(message);
};

NotificationHub.setListener(mListener);
}

public void addNotification(Intent notification) {
List<Intent> toUpdate = mNotifications.getValue();
if(toUpdate == null) {
toUpdate = new ArrayList<Intent>();
}
toUpdate.add(0, notification);
mNotifications.postValue(toUpdate);
}

public void clearNotifications() {
List<Intent> toUpdate = mNotifications.getValue();
if (toUpdate == null) {
toUpdate = new ArrayList<Intent>();
} else {
toUpdate.clear();
}
mNotifications.postValue(toUpdate);
}

public LiveData<List<Intent>> getNotificationList() {
return mNotifications;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar"
android:exported="false">
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

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