Badge on app icon for Android doesn't show even after implementing ngCordova (cordova-plugin-badge) and phonegap-plugin-push - angularjs

I will really appreciate if anyone can help me with this issue that has been bugging me for days.
I have a hybrid app created using the Ionic framework, which I have implemented push notifications on (via phonegap-plugin-push). The push notifications work fine, but what I want is for the push notification (i.e. GCM payload) to send a badge count/number over to the application, and the application will take that count/number and displays it as a badge beside the app icon. My code works perfectly for iOS devices given that badges are already inbuilt, but I have difficulties with implementing the same idea (badges) on the Android platform.
I am aware that due to badges not being inbuilt into the Android platform, some devices might not be supported, but at least I want it to work for some devices (i.e. Samsung, Sony). I have done a lot of research, most prominently:
cordova-plugin-badge (https://github.com/katzer/cordova-plugin-badge) which stated in the documentation is supposed to work for both iOS and certain Android devices, but it doesn't work on any Android devices at all for me. Note that the Android devices I have been testing on are emulators from Genymotion, which I have set up Google Play Services on and are able to receive push notifications and function almost like a real device, will that be an issue?
ShortcutBadger (https://github.com/leolin310148/ShortcutBadger) which only has documentation for native Android implementation and supposedly utilised by cordova-plugin-badge as stated above to extend the support to hybrid Android apps, but this has been unable to help me at all.
My index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<title></title>
<link href="css/style.css" rel="stylesheet">
<script src="lib/ionic/js/ionic.bundle.js"></script>
<script src="lib/ionic-platform-web-client/dist/ionic.io.bundle.min.js"></script>
<script src="js/ng-cordova.js"></script>
<script src="cordova.js"></script>
<script src="js/app.js"></script>
</head>
<body ng-app="starter">
<ion-pane>
<ion-header-bar class="bar-stable">
<h1 class="title">Trade Deals</h1>
</ion-header-bar>
<ion-content ng-controller="badgeController">
<div>Number of deals pending now: </div>
<div class="deals"></div>
<button class="button" ng-click="setBadge(10)">Set badge 10</button>
<button class="button" ng-click="hasPermission()">Show permission</button>
<button class="button" ng-click="get()">Get badge count</button>
<button class="button" ng-click="clear()">Clear badge count</button>
<button class="button" ng-click="increase()">Increase by 1</button>
<button class="button" ng-click="decrease()">Decrease by 1</button>
</ion-content>
</ion-pane>
</body>
</html>
My app.js:
angular.module('starter', ['ionic', 'ngCordova'])
/*
* do a ionic.push register() every time the app launches for the first time
* so that it is guaranteed that there is always a valid device token for GCM/APNS
*/
.run(function($ionicPlatform, $cordovaBadge) {
$ionicPlatform.ready(function() {
console.log("Device platform is "+device.platform);
var push = new Ionic.Push({
"debug": true,
"onNotification": function(notification) {
console.log("notification received!!!");
var payload = notification.payload;
var payloadStr = JSON.stringify(payload, null, 4);
var notiStr = JSON.stringify(notification, null, 4);
console.log("notification: "+notiStr);
var countIndex = notiStr.indexOf("count"); // extracting badge count from the GCM payload
var badgeIndex = countIndex + 9;
var badgeNo;
if (!isNaN(notiStr[badgeIndex+1])) {
badgeNo = notiStr.substr(badgeIndex,badgeIndex+2);
}
else {
badgeNo = notiStr[badgeIndex];
}
if (device.platform == "Android") {
$cordovaBadge.set(badgeNo);
}
},
"onRegister": function(data) {
console.log(data.token);
},
"pluginConfig": {
"android": {
"sound": "true",
"badge": "true",
"icon": "icon",
"iconColor": "lime"
},
"ios": {
"alert": "true",
"badge": "true",
"sound": "true"
},
}
});
push.register(function(token) {
console.log("My Device token:",token.token);
//window.alert("The token is "+token.token);
push.saveToken(token); // persist the token in the Ionic Platform so that it doesn't change on multiple launches
});
$cordovaBadge.get().then(function(badge) {
document.querySelector(".deals").innerHTML = badge;
});
});
})
.controller("badgeController", function($scope, $ionicPlatform, $cordovaBadge) {
console.log("inside badgeController");
$ionicPlatform.ready(function() {
$ionicPlatform.on('resume', function() {
$cordovaBadge.get().then(function(badge) {
document.querySelector(".deals").innerHTML = badge;
});
});
//$cordovaBadge.configure({autoClear: true}); // configure to clear all notifications whenever user opens the app
$scope.setBadge = function(value) {
console.log("inside setBadge");
$cordovaBadge.hasPermission().then(function(result) {
$cordovaBadge.set(value);
window.alert("Badge count is "+value);
}, function(error) {
console.log(JSON.stringify(error)); // display error message
});
}
$scope.hasPermission = function() {
console.log("inside hasPermission");
$cordovaBadge.hasPermission().then(function(result) {
window.alert("User has permission: "+result);
console.log("device has permission");
}, function(error) {
console.log(JSON.stringify(error)); // display error message
});
}
$scope.get = function() {
console.log("inside get");
$cordovaBadge.hasPermission().then(function(result) {
$cordovaBadge.get().then(function(badge) {
if (badge>=0) {
document.querySelector(".deals").innerHTML = badge;
}
})
}, function(error) {
console.log(JSON.stringify(error)); // display error message
});
}
$scope.clear = function() {
console.log("inside clear");
$cordovaBadge.hasPermission().then(function(result) {
$cordovaBadge.clear();
window.alert("Cleared badge count");
}, function(error) {
console.log(JSON.stringify(error)); // display error message
});
}
$scope.increase = function() {
console.log("inside increase");
$cordovaBadge.hasPermission().then(function(result) {
$cordovaBadge.increase();
window.alert("Increased badge count");
}, function(error) {
console.log(JSON.stringify(error)); // display error message
});
}
$scope.decrease = function() {
console.log("inside decrease");
$cordovaBadge.hasPermission().then(function(result) {
$cordovaBadge.decrease();
window.alert("Good job!");
//window.alert("Decreased badge count");
}, function(error) {
console.log(JSON.stringify(error)); // display error message
});
}
});
});
Also, is the issue that the app icon has to be converted to a widget in order for the badges to work? I am not sure how the cordova-plugin-badge is implemented and the instructions didn't say anything about widgets being needed for Android.
Thank you and any help/tips is appreciated :) I have been troubleshooting this for days and it's rather frustrating.

Stock Android does not offer this functionality at the moment on the standard launcher.
Certain manufacturers (e.g. Samsung notably) have included this functionality into their customised Android launchers. Also some 3rd-party launchers (e.g. Nova Launcher) have included an API to accomplish this.
You may want to check following links for further explaination:
How does Facebook add badge numbers on app icon in Android?
Does Samsung modifies it's Android ROMs to have badges on email and SMS icons?
How to make application badge on android?
Regards

Related

Shaka Player Start Video in full screen

I have the basic shaka player code. I want to start the video on full screen. Please tell me if it is possible.
HTML
<!DOCTYPE html>
<html style="height:100%">
<head>
<!-- Shaka Player compiled library: -->
<script src="dist/shaka-player.compiled.js"></script>
<!-- Your application source: -->
<script src="myapp.js"></script>
</head>
<body style="height:100%">
<video id="video"
width="100%"
height="100%"
poster="//shaka-player-demo.appspot.com/assets/poster.jpg"
controls autoplay></video>
</body>
</html>
myapp.js
// myapp.js
var manifestUri =
'./asd.mp4';
function initApp() {
// Install built-in polyfills to patch browser incompatibilities.
shaka.polyfill.installAll();
// Check to see if the browser supports the basic APIs Shaka needs.
if (shaka.Player.isBrowserSupported()) {
// Everything looks good!
initPlayer();
} else {
// This browser does not have the minimum set of APIs we need.
console.error('Browser not supported!');
}
}
function initPlayer() {
// Create a Player instance.
var video = document.getElementById('video');
var player = new shaka.Player(video);
// Attach player to the window to make it easy to access in the JS console.
window.player = player;
// Listen for error events.
player.addEventListener('error', onErrorEvent);
// Try to load a manifest.
// This is an asynchronous process.
player.load(manifestUri).then(function() {
// This runs if the asynchronous load is successful.
console.log('The video has now been loaded!');
}).catch(onError); // onError is executed if the asynchronous load fails.
}
function onErrorEvent(event) {
// Extract the shaka.util.Error object from the event.
onError(event.detail);
}
function onError(error) {
// Log the error.
console.error('Error code', error.code, 'object', error);
}
document.addEventListener('DOMContentLoaded', initApp);
I did this using the below code
player.load(manifestUri).then(function() {
// This runs if the asynchronous load is successful.
console.log('The video has now been loaded!');
video.requestFullscreen().catch(err => {
console.log(err)
});
}).catch(onError); // onError is executed if the asynchronous load fails.
Please let me know if there is a better solution

How to bind remote JSON data to a Polymer vaadin-grid?

First time using this web component... I'm able to bind JSON data in a var to a vaadin-grid (w/ polymer 1.0), but am missing something basic about getting the JSON data from a url into the grid.
Here's the most simple example I could create, that worked with hard-coded JSON and now have used some of the examples from the Vaadin website to attempt to pull the data from a URL.
<head>
// import statements same as in my example that works with hard coded JSON
<script>
function getJSON(url, callback) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
callback(JSON.parse(xhr.responseText));
}
};
xhr.open('GET', url, true);
xhr.send();
}
</script>
</head>
<body>
<h2>Vaadin Grid - example </h2><br>
<vaadin-grid selection-mode="multi">
<table>
<col name="name">
<col name="city">
</table>
</vaadin-grid>
<script>
var grid = grid || document.querySelector('vaadin-grid');
HTMLImports.whenReady(function() {
grid.items = function(params, callback) {
var url = 'https://.../simple-data.json';
getJSON(url, function(data) {
callback(data[0]);
});
};
});
</script>
And simple-data.json URL returns this:
[ { "name": "Jose Romero", "city": "Monteray" }, { "name": "Chuy Diez", "city": "Los Angeles" }, { "name": "Inez Vega", "city": "San Diego" } ]
Where am I going wrong? Thanks in advance.
Binding is easily done using the Polymer 1.0 iron-ajax component. Here's the working code:
<head>
// import statements same as in my example that works with hard coded JSON
<link rel="import" href="iron-ajax/iron-ajax.html">
<link rel="import" href="vaadin-grid/vaadin-grid.html">
</head>
<body>
<h2>Vaadin Grid - working example </h2><br>
<template is="dom-bind">
<iron-ajax
auto
url = "http://hostname/.../simple-data.json"
handle-as="json"
last-response="{{gridData}}" ></iron-ajax>
<vaadin-grid selection-mode="multi" items="{{gridData}}">
<table>
<col name="name">
<col name="city">
</table>
</vaadin-grid>
</template>
<script>
</script>
</body>
I still would like to learn how it's done using the JavaScript code in the Vaadin documentation Remote Data Any tips?
Answering my own question again: to bind JSON to a vaadin-grid using JavaScript instead of using the Polymer iron-ajax component simply add this script section to the bottom of the body. It adds an event listener for WebComponentsReady.
<script type="text/javascript">
window.addEventListener('WebComponentsReady', function() {
var grid = document.querySelector('vaadin-grid');
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
var json = JSON.parse(xhr.responseText);
grid.items = json;
}
}
};
xhr.open('GET', 'http://<your_url>', true);
xhr.send();
});
</script>
For others getting started with vaadin Polymer components they have a series of very short, but excellent tutorials - search YouTube for "vaadin elementary school" to find them.

How to share a photo to Instagram with Ionic

I am trying to share a taken photo to Instagram. I have installed the social share plugin from ngCordova website
But I am not able to get it to work. When running it I get no errors.
I get a success response but the image is not posted on the wall of Instagram.
Here is a print screen from the logs (xcode -> running from actual device to test).
Can anybody see what I am doing wrong?
Here is part of my controller code:
app.controller('CameraCtrl', function($scope, $cordovaCamera, $cordovaSocialSharing, $rootScope, $state){
$scope.takePicture = function(){
var options = {
quality: 75,
destinationType: Camera.DestinationType.DATA_URI,
sourceType: Camera.PictureSourceType.CAMERA,
encodingType: Camera.EncodingType.JPEG,
saveToPhotoAlbum: true,
correctOrientation:true
};
$cordovaCamera.getPicture(options)
.then(function(imageURI){
var imagePlaceholder = document.getElementById('placeholderPicture');
imagePlaceholder.src = imageURI;
$rootScope.imgShare = imageURI;
//$scope.imgURI = "data:image/jpeg;base64," + imageURI;
//$state.go('app.camera', {image: $scope.imgURI});
//console.log('camera data: ' + angular.toJson(imageURI));
}, function(error){
console.log('error camera data: ' + angular.toJson(imageURI));
});
}
$scope.shareViaInstagram = function(message, image){
socialType = "instagram";
message = "test";
image = $rootScope.imgShare;
$cordovaSocialSharing.shareVia(socialType, message, image, null).then(function(result) {
console.log('image shared to Instagram ', result);
console.log('dddd', image);
console.log('######', $rootScope.imgShare);
//$state.go('app.finish');
}, function(err) {
console.log('error in sharing to Instagram ', err);
});
}
});
Part of my html code:
<div class="wrapperCamera">
<div class="cameraContent padding">
<img id="placeholderPicture" ng-src="{{imgShare}}">
<br>
<h2 class="customH2Camera">looking good!</h2>
<br><br>
<div class="socialIcons">
<img src="img/iconInstagram.svg" width="40">
<img src="img/iconFacebook.svg" width="40">
</div>
</div><!-- end cameraContent -->
</div><!-- end WrapperCamera -->
module.controller('ThisCtrl', function($scope, $cordovaInstagram) {
// Get image from camera, base64 is good. See the
// $cordovaCamera docs for more info
$cordovaInstagram.share($scope.image.data, $scope.image.caption).then(function() {
// Worked
}, function(err) {
// Didn't work
});
})
Wrap your plugin call within the deviceready event of cordova. It makes sure that device is fully loaded before making a call to the plugin.
document.addEventListener("deviceready", function () {
// your plugin call here
});
You can also use $ionicPlatform.ready(function() {});
Read this for more info: ngCordova common issues

AngularJS warning when leaving page

I know there are a few posts similar to this but I simply can't get any of them to work for me as intended. I'm trying to setup an event handler to listen to a location change on a specific scope. The code looks like this:
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title></title>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
</head>
<body>
<div ng-app="myApp" ng-controller="verifyViewChange">
Test
</div>
<script>
var app = angular.module('myApp', []);
app.controller('verifyViewChange', function ($location, $scope) {
$scope.$on('$locationChangeStart', function (event) {
event.preventDefault();
alert("I'm preventing you from leaving the page");
});
});
</script>
</body>
</html>
When I load the page I get the warning, but not when clicking on the link. What do I need to do to make it work?
You should use the native 'beforeunload' event by adding it to the window.
Below is an example:
$scope.addUnloadEvent = function(){
if (window.addEventListener) {
window.addEventListener("beforeunload", handleUnloadEvent);
} else {
//For IE browsers
window.attachEvent("onbeforeunload", handleUnloadEvent);
}
}
function handleUnloadEvent(event) {
event.returnValue = "Your warning text";
};
//Call this when you want to remove the event, example, if users fills necessary info
$scope.removeUnloadEvent = function(){
if (window.removeEventListener) {
window.removeEventListener("beforeunload", handleUnloadEvent);
} else {
window.detachEvent("onbeforeunload", handleUnloadEvent);
}
}
//You could add the event when validating a form, for example
$scope.validateForm = function(){
if($scope.yourform.$invalid){
$scope.addUnloadEvent();
return;
}
else{
$scope.removeUnloadEvent();
}
}
The [fix above] is great just added this bit to the handleUnloadEvent...
function handleUnloadEvent(event) {
/*
This bit here theres another bind that says if this fields initial value is
not the same as its current value add the class of input-changed if it is
remove the class...so you can flag any page ya want to prompt a dialog based
on presence of a class on an input.
*/
var changeCheckCount = $('.input-changed').length;
console.log('changeCheckCount',changeCheckCount);
if(changeCheckCount === 0)
{
$scope.removeUnloadEvent();
}
else if(changeCheckCount > 0)
{
event.returnValue = "You have Unsaved changes do you really want to leave?";
}
Allows you to say if you want dialog to reload or leave page with just a class...Suppose you could bind the dialog too by finding the first one with .input-changed and have a data attribute on it with the message to show as the dialog.
Below is working example , it may helpful to you:
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<div ng-app="myApp" ng-controller="verifyViewChange">
Test
</div>
<script>
var app = angular.module('myApp', []);
app.controller('verifyViewChange', function ($location, $scope) {
$scope.funConfirm = function () {
var retVal = confirm("I'm preventing you from leaving the page");
if (retVal == true) {
return false;
} else {
event.preventDefault();
return false;
}
}
});
</script>

window.postMessage between iframe and its parent with Angular: does anyone have a working example?

Does anyone have a working example of how to send and receive window.postMessage() calls in angular? I found the ng-post-message module on github and ngmodules, but I look at that code and it doesn't make a whole lot of sense to me and the documentation is lacking a working example.
Edit: to add my failed attempt
The view
<div simulation-host element="thing in things"></div>
</div>
<div id="debugConsole">
<h1>MESSAGE CONSOLE</h1>
<p id="debugText"></p>
</div>
The model
$scope.things =
[
{
"location" : "Foobar",
"resource" : $sce.trustAsResourceUrl("http://external.domain:14168/Foo/Bar"),
"title" : "Launch"
}
];
My attempt at a directive
var simulationFrameHost = angular.module('proxy.directives', []);
simulationFrameHost.config(function ($sceDelegateProvider){
//URL Regex provided by Microsoft Patterns & Practices.
$sceDelegateProvider.resourceUrlWhitelist(['^(ht|f)tp(s?)\:\/\/[0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*(:(0-9)*)*(\/?)([a-zA-Z0-9\-\.\?\,\'\/\\\+&%\$#_]*)?$','self']);
});
simulationFrameHost.directive('simulationHost', ['$window',function($window) {
return {
retrict: 'ACE',
transclude: 'element',
replace: true,
scope: true,
template: [
'<ul>',
'<li>',
'<span>',
'<a href="#">',
'{{thing.location}}',
'</a>',
'</span>',
'<messenger>',
'<iframe ng-src="{{thing.resource}}" />',
'</messenger>',
'</li>',
'</ul>'
].join(''),
compile: function (tElement, tAttrs, transclude) {
var interval;
var show = function(msg)
{
var debugText = document.getElementById("debugText");
if(debugText){
debugText.innerHTML += msg + "<br/>";
}
};
var rpt = document.createAttribute('ng-repeat');
rpt.value = tAttrs.element;
console.log(tAttrs.element);
tElement[0].children[0].attributes.setNamedItem(rpt);
$(tElement[0].children[0].children[0].children[0]).on("click", function(event){
console.log(event);
var iframe = tElement[0].children[0].children[1].children[0].contentWindow;
show("Initiating connection with: " + event.currentTarget.host);
var message = {
action: 'syn',
param: 'connection'
};
interval = setInterval(function(){
//*****************************************
iframe.postMessage(JSON.stringify(message), 'http://'+ event.currentTarget.host);
//*****************************************
}, 500);
return false;
});
}
}
}]);
Working legacy code that I am trying to adapt to Angular
Note that this code uses a popup rather than an iframe; ran into the complication that IE's postMessage between windows is broken so have to fall back to iframe.
Markup
<body>
<div id="debugConsole">
<h1>MESSAGE CONSOLE</h1>
<p id="debugText"></p>
</div>
<h1>This is a test</h1>
<ul>
<li>
<a href= "http://external.domain:14168/Foo/Bar" target="_blank" ><p>Foobar</p></a>
</li>
</ul>
<script src="js/jquery-1.10.2.min.js"></script>
<script src="bower_components/angular/angular.js"></script>
<script src="bower_components/angular-animate/angular-animate.js"></script>
<script src="bower_components/angular-route/angular-route.js"></script>
<script src="bower_components/angular-resource/angular-resource.js"></script>
<script src="js/SCORM_API_wrapper.js"></script>
<script src="js/json2.js"></script>
<script src="js/plugins.js"></script>
<script src="js/index.js"></script>
</body>
index.js
$('a').on("click",function(event){
console.log(event);
var pop = window.open(event.currentTarget.href, 'poop');
show("Initiating connection with: " + event.currentTarget.host);
var message = {
action: 'syn',
param: 'connection',
};
interval = setInterval(function(){
pop.postMessage(JSON.stringify(message), 'http://'+ event.currentTarget.host);
}, 500);
return false;
});
$(window).on("message", function(e) {
clearInterval(interval);
var eventData = JSON.parse(e.originalEvent.data);
show("Message received from: " + e.originalEvent.origin);
if(eventData.action) {
switch (eventData.action) {
case 'syn-ack':
ack(e.originalEvent, eventData.param, eventData.value);
break;
case "set":
show("Set request received: " + e.originalEvent.data);
set(eventData.param, eventData.value);
break;
case "get":
show("Get request received: " + e.originalEvent.data);
var value = get(eventData.param);
var response = {
action: "response",
type: "get",
param: eventData.param,
value: value
};
e.originalEvent.source.postMessage(JSON.stringify(response), channel);
break;
}
}
});
In my directive's compile, I'm trying to wire up a click event to the generated anchor tag. I'm trying to get the click to post a message to the iframe, but iframe.postMessage is doing nothing. It just goes off into the nether, and I've been working on this since 10 this morning. My eyes are starting to glaze over : p
Edit: Adding an extension requirement (now that I have functioning code) for a general messaging directive between separate containers, regardless of the container type:
1)iframe to parent
2)window to window (<=yes, I already know this doesn't work in IE)
I had legacy code working that performed window to window messaging by having the window that spawned
the second post a "syn" message to it immediately after creating it. The second window then received the message as a "syn" and stored the sender as a messageHandle so that it could maintain a channel to post return messages then returned a "syn-ack." The originator followed up with an "ack" and the secondary window received the ack and proceeded with its work. (If the ack did not return before the timeout, I logged that the connection had failed and then the secondary window polled on an interval to attempt to restore the connection)
Just came across this post, this may help you.
(function() {
'use strict';
angular
.module('postmessage')
.factory('iFrameMessagingService', iFrameMessagingService);
iFrameMessagingService.$inject = ['$window', '$location', '$rootScope', '$log'];
function iFrameMessagingService($window, $location, $rootScope, $log) {
var service = {
sendMessage : sendMessage
};
activate();
return service;
function activate(){
activateIncomingMessageHandler();
}
function activateIncomingMessageHandler(){
$window.addEventListener('message', function(event){
if (typeof(event.data) !== 'undefined'){
// handle message
}
});
}
function sendMessage(message){
// Dispatch the event.
$log.debug(message);
if($window.parent !== $window){
$window.parent.postMessage(message, '*');
}
}
}
})();
I couldn't get this working with an Angular directive. I pulled a wasted all nighter trying to get this done "The Right Way" and wish I had ejected that idea sooner because my requirements didn't really warrant it. This thing doesn't have to scale because it is purpose build software for providing a messaging proxy between X-Domain systems.
'use strict'
var app = angular.module('domain.system.controllers', ['services.proxy.mine']);
app.controller('ProxyCtrl', ['$scope', '$routeParams', '$window', '$sce', 'MyService',
function ( $scope, $routeParams, $window, $sce, MyService)
{
$($window).on("message", function(e){
var message = JSON.parse(e.originalEvent.data);
if(message.recipient){
switch(message.recipient){
case: "ProxyCtrl":
//handle message;
break;
}
}
}
}
]);
I am 100% interested in a detailed explanation of how to convert this code into a functioning directive.

Resources