2017-10-26 13:03:08 +00:00
|
|
|
// (C) Copyright 2015 Martin Dougiamas
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
import { Injectable } from '@angular/core';
|
2018-01-08 13:42:08 +00:00
|
|
|
import { Platform, App, NavController } from 'ionic-angular';
|
2017-10-26 13:03:08 +00:00
|
|
|
import { Keyboard } from '@ionic-native/keyboard';
|
|
|
|
import { Network } from '@ionic-native/network';
|
|
|
|
|
|
|
|
import { CoreDbProvider } from './db';
|
|
|
|
import { CoreLoggerProvider } from './logger';
|
2017-11-14 07:58:20 +00:00
|
|
|
import { SQLiteDB } from '../classes/sqlitedb';
|
2017-10-26 13:03:08 +00:00
|
|
|
|
2018-01-15 07:22:00 +00:00
|
|
|
/**
|
|
|
|
* Data stored for a redirect to another page/site.
|
|
|
|
*/
|
2017-11-21 15:35:41 +00:00
|
|
|
export interface CoreRedirectData {
|
2018-01-15 07:22:00 +00:00
|
|
|
/**
|
|
|
|
* ID of the site to load.
|
|
|
|
* @type {string}
|
|
|
|
*/
|
2017-11-21 15:35:41 +00:00
|
|
|
siteId?: string;
|
2018-01-15 07:22:00 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Name of the page to redirect to.
|
|
|
|
* @type {string}
|
|
|
|
*/
|
|
|
|
page?: string;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Params to pass to the page.
|
|
|
|
* @type {any}
|
|
|
|
*/
|
|
|
|
params?: any;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Timestamp when this redirect was last modified.
|
|
|
|
* @type {number}
|
|
|
|
*/
|
2017-11-21 15:35:41 +00:00
|
|
|
timemodified?: number;
|
|
|
|
};
|
|
|
|
|
2017-10-26 13:03:08 +00:00
|
|
|
/**
|
|
|
|
* Factory to provide some global functionalities, like access to the global app database.
|
|
|
|
* @description
|
|
|
|
* Each service or component should be responsible of creating their own database tables. Example:
|
|
|
|
*
|
|
|
|
* constructor(appProvider: CoreAppProvider) {
|
|
|
|
* this.appDB = appProvider.getDB();
|
|
|
|
* this.appDB.createTableFromSchema(this.tableSchema);
|
|
|
|
* }
|
|
|
|
*/
|
|
|
|
@Injectable()
|
|
|
|
export class CoreAppProvider {
|
2018-01-12 13:28:46 +00:00
|
|
|
protected DBNAME = 'MoodleMobile';
|
|
|
|
protected db: SQLiteDB;
|
|
|
|
protected logger;
|
|
|
|
protected ssoAuthenticationPromise : Promise<any>;
|
|
|
|
protected isKeyboardShown: boolean = false;
|
2017-10-26 13:03:08 +00:00
|
|
|
|
2018-01-08 13:42:08 +00:00
|
|
|
constructor(dbProvider: CoreDbProvider, private platform: Platform, private keyboard: Keyboard, private appCtrl: App,
|
2017-10-26 13:03:08 +00:00
|
|
|
private network: Network, logger: CoreLoggerProvider) {
|
|
|
|
this.logger = logger.getInstance('CoreAppProvider');
|
2017-12-01 07:51:07 +00:00
|
|
|
this.db = dbProvider.getDB(this.DBNAME);
|
2017-10-26 13:03:08 +00:00
|
|
|
|
|
|
|
this.keyboard.onKeyboardShow().subscribe((data) => {
|
|
|
|
this.isKeyboardShown = true;
|
|
|
|
|
|
|
|
});
|
|
|
|
this.keyboard.onKeyboardHide().subscribe((data) => {
|
|
|
|
this.isKeyboardShown = false;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if the browser supports mediaDevices.getUserMedia.
|
|
|
|
*
|
|
|
|
* @return {boolean} Whether the function is supported.
|
|
|
|
*/
|
|
|
|
canGetUserMedia() : boolean {
|
|
|
|
return !!(navigator && navigator.mediaDevices && navigator.mediaDevices.getUserMedia);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if the browser supports MediaRecorder.
|
|
|
|
*
|
|
|
|
* @return {boolean} Whether the function is supported.
|
|
|
|
*/
|
|
|
|
canRecordMedia() : boolean {
|
|
|
|
return !!(<any>window).MediaRecorder;
|
2018-01-08 13:42:08 +00:00
|
|
|
}
|
2017-10-26 13:03:08 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Closes the keyboard.
|
|
|
|
*/
|
|
|
|
closeKeyboard() : void {
|
|
|
|
if (this.isMobile()) {
|
|
|
|
this.keyboard.close();
|
|
|
|
}
|
2018-01-08 13:42:08 +00:00
|
|
|
}
|
2017-10-26 13:03:08 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the application global database.
|
|
|
|
*
|
2017-11-14 07:58:20 +00:00
|
|
|
* @return {SQLiteDB} App's DB.
|
2017-10-26 13:03:08 +00:00
|
|
|
*/
|
2017-11-14 07:58:20 +00:00
|
|
|
getDB() : SQLiteDB {
|
2017-10-26 13:03:08 +00:00
|
|
|
return this.db;
|
2018-01-08 13:42:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the app's root NavController.
|
|
|
|
*
|
|
|
|
* @return {NavController} Root NavController.
|
|
|
|
*/
|
|
|
|
getRootNavController() : NavController {
|
|
|
|
// getRootNav is deprecated. Get the first root nav, there should always be one.
|
|
|
|
return this.appCtrl.getRootNavs()[0];
|
|
|
|
}
|
2017-10-26 13:03:08 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks if the app is running in a desktop environment (not browser).
|
|
|
|
*
|
|
|
|
* @return {boolean} Whether the app is running in a desktop environment (not browser).
|
|
|
|
*/
|
|
|
|
isDesktop() : boolean {
|
|
|
|
let process = (<any>window).process;
|
|
|
|
return !!(process && process.versions && typeof process.versions.electron != 'undefined');
|
2018-01-08 13:42:08 +00:00
|
|
|
}
|
2017-10-26 13:03:08 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if the keyboard is visible.
|
|
|
|
*
|
|
|
|
* @return {boolean} Whether keyboard is visible.
|
|
|
|
*/
|
|
|
|
isKeyboardVisible() : boolean {
|
|
|
|
return this.isKeyboardShown;
|
2018-01-08 13:42:08 +00:00
|
|
|
}
|
2017-10-26 13:03:08 +00:00
|
|
|
|
2017-12-08 12:45:30 +00:00
|
|
|
/**
|
|
|
|
* Check if the app is running in a Linux environment.
|
|
|
|
*
|
|
|
|
* @return {boolean} Whether it's running in a Linux environment.
|
|
|
|
*/
|
|
|
|
isLinux() : boolean {
|
|
|
|
if (!this.isDesktop()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
var os = require('os');
|
|
|
|
return os.platform().indexOf('linux') === 0;
|
|
|
|
} catch(ex) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if the app is running in a Mac OS environment.
|
|
|
|
*
|
|
|
|
* @return {boolean} Whether it's running in a Mac OS environment.
|
|
|
|
*/
|
|
|
|
isMac() : boolean {
|
|
|
|
if (!this.isDesktop()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
var os = require('os');
|
|
|
|
return os.platform().indexOf('darwin') === 0;
|
|
|
|
} catch(ex) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-26 13:03:08 +00:00
|
|
|
/**
|
|
|
|
* Checks if the app is running in a mobile or tablet device (Cordova).
|
|
|
|
*
|
|
|
|
* @return {boolean} Whether the app is running in a mobile or tablet device.
|
|
|
|
*/
|
|
|
|
isMobile() : boolean {
|
|
|
|
return this.platform.is('cordova');
|
2018-01-08 13:42:08 +00:00
|
|
|
}
|
2017-10-26 13:03:08 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns whether we are online.
|
|
|
|
*
|
|
|
|
* @return {boolean} Whether the app is online.
|
|
|
|
*/
|
|
|
|
isOnline() : boolean {
|
|
|
|
let online = this.network.type !== null && this.network.type != Connection.NONE && this.network.type != Connection.UNKNOWN;
|
|
|
|
// Double check we are not online because we cannot rely 100% in Cordova APIs. Also, check it in browser.
|
|
|
|
if (!online && navigator.onLine) {
|
|
|
|
online = true;
|
|
|
|
}
|
|
|
|
return online;
|
2018-01-08 13:42:08 +00:00
|
|
|
}
|
2017-10-26 13:03:08 +00:00
|
|
|
|
2017-12-28 15:10:26 +00:00
|
|
|
/**
|
2017-10-26 13:03:08 +00:00
|
|
|
* Check if device uses a limited connection.
|
|
|
|
*
|
|
|
|
* @return {boolean} Whether the device uses a limited connection.
|
|
|
|
*/
|
|
|
|
isNetworkAccessLimited() : boolean {
|
|
|
|
let type = this.network.type;
|
|
|
|
if (type === null) {
|
|
|
|
// Plugin not defined, probably in browser.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
let limited = [Connection.CELL_2G, Connection.CELL_3G, Connection.CELL_4G, Connection.CELL];
|
|
|
|
return limited.indexOf(type) > -1;
|
2018-01-08 13:42:08 +00:00
|
|
|
}
|
2017-10-26 13:03:08 +00:00
|
|
|
|
2017-12-08 12:45:30 +00:00
|
|
|
/**
|
|
|
|
* Check if the app is running in a Windows environment.
|
|
|
|
*
|
|
|
|
* @return {boolean} Whether it's running in a Windows environment.
|
|
|
|
*/
|
|
|
|
isWindows() : boolean {
|
|
|
|
if (!this.isDesktop()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
var os = require('os');
|
|
|
|
return os.platform().indexOf('win') === 0;
|
|
|
|
} catch(ex) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-26 13:03:08 +00:00
|
|
|
/**
|
|
|
|
* Open the keyboard.
|
|
|
|
*/
|
|
|
|
openKeyboard() : void {
|
|
|
|
// Open keyboard is not supported in desktop and in iOS.
|
|
|
|
if (this.isMobile() && !this.platform.is('ios')) {
|
|
|
|
this.keyboard.show();
|
|
|
|
}
|
2018-01-08 13:42:08 +00:00
|
|
|
}
|
2017-10-26 13:03:08 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Start an SSO authentication process.
|
|
|
|
* Please notice that this function should be called when the app receives the new token from the browser,
|
|
|
|
* NOT when the browser is opened.
|
|
|
|
*/
|
|
|
|
startSSOAuthentication() : void {
|
2017-12-08 14:15:27 +00:00
|
|
|
let cancelTimeout,
|
|
|
|
resolvePromise;
|
|
|
|
|
2017-10-26 13:03:08 +00:00
|
|
|
this.ssoAuthenticationPromise = new Promise((resolve, reject) => {
|
2017-12-08 14:15:27 +00:00
|
|
|
resolvePromise = resolve;
|
2017-10-26 13:03:08 +00:00
|
|
|
|
|
|
|
// Resolve it automatically after 10 seconds (it should never take that long).
|
2017-12-08 14:15:27 +00:00
|
|
|
cancelTimeout = setTimeout(() => {
|
2017-10-26 13:03:08 +00:00
|
|
|
this.finishSSOAuthentication();
|
|
|
|
}, 10000);
|
2017-12-08 14:15:27 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
// Store the resolve function in the promise itself.
|
|
|
|
(<any>this.ssoAuthenticationPromise).resolve = resolvePromise;
|
2017-10-26 13:03:08 +00:00
|
|
|
|
2017-12-08 14:15:27 +00:00
|
|
|
// If the promise is resolved because finishSSOAuthentication is called, stop the cancel promise.
|
|
|
|
this.ssoAuthenticationPromise.then(() => {
|
|
|
|
clearTimeout(cancelTimeout);
|
2017-10-26 13:03:08 +00:00
|
|
|
});
|
2018-01-08 13:42:08 +00:00
|
|
|
}
|
2017-10-26 13:03:08 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Finish an SSO authentication process.
|
|
|
|
*/
|
|
|
|
finishSSOAuthentication() : void {
|
|
|
|
if (this.ssoAuthenticationPromise) {
|
|
|
|
(<any>this.ssoAuthenticationPromise).resolve && (<any>this.ssoAuthenticationPromise).resolve();
|
|
|
|
this.ssoAuthenticationPromise = undefined;
|
|
|
|
}
|
2018-01-08 13:42:08 +00:00
|
|
|
}
|
2017-10-26 13:03:08 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if there's an ongoing SSO authentication process.
|
|
|
|
*
|
|
|
|
* @return {boolean} Whether there's a SSO authentication ongoing.
|
|
|
|
*/
|
|
|
|
isSSOAuthenticationOngoing() : boolean {
|
|
|
|
return !!this.ssoAuthenticationPromise;
|
2018-01-08 13:42:08 +00:00
|
|
|
}
|
2017-10-26 13:03:08 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a promise that will be resolved once SSO authentication finishes.
|
|
|
|
*
|
|
|
|
* @return {Promise<any>} Promise resolved once SSO authentication finishes.
|
|
|
|
*/
|
|
|
|
waitForSSOAuthentication() : Promise<any> {
|
|
|
|
return this.ssoAuthenticationPromise || Promise.resolve();
|
2018-01-08 13:42:08 +00:00
|
|
|
}
|
2017-10-26 13:03:08 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieve redirect data.
|
|
|
|
*
|
2017-11-21 15:35:41 +00:00
|
|
|
* @return {CoreRedirectData} Object with siteid, state, params and timemodified.
|
2017-10-26 13:03:08 +00:00
|
|
|
*/
|
2017-11-21 15:35:41 +00:00
|
|
|
getRedirect() : CoreRedirectData {
|
2017-10-26 13:03:08 +00:00
|
|
|
if (localStorage && localStorage.getItem) {
|
|
|
|
try {
|
2017-11-21 15:35:41 +00:00
|
|
|
let data: CoreRedirectData = {
|
|
|
|
siteId: localStorage.getItem('mmCoreRedirectSiteId'),
|
|
|
|
page: localStorage.getItem('mmCoreRedirectState'),
|
2017-10-26 13:03:08 +00:00
|
|
|
params: localStorage.getItem('mmCoreRedirectParams'),
|
2017-11-21 15:35:41 +00:00
|
|
|
timemodified: parseInt(localStorage.getItem('mmCoreRedirectTime'), 10)
|
2017-10-26 13:03:08 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
if (data.params) {
|
|
|
|
data.params = JSON.parse(data.params);
|
|
|
|
}
|
|
|
|
|
|
|
|
return data;
|
|
|
|
} catch(ex) {
|
|
|
|
this.logger.error('Error loading redirect data:', ex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return {};
|
2018-01-08 13:42:08 +00:00
|
|
|
}
|
2017-10-26 13:03:08 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Store redirect params.
|
|
|
|
*
|
|
|
|
* @param {string} siteId Site ID.
|
|
|
|
* @param {string} page Page to go.
|
2017-11-21 15:35:41 +00:00
|
|
|
* @param {any} params Page params.
|
2017-10-26 13:03:08 +00:00
|
|
|
*/
|
2017-11-21 15:35:41 +00:00
|
|
|
storeRedirect(siteId: string, page: string, params: any) : void {
|
2017-10-26 13:03:08 +00:00
|
|
|
if (localStorage && localStorage.setItem) {
|
|
|
|
try {
|
|
|
|
localStorage.setItem('mmCoreRedirectSiteId', siteId);
|
|
|
|
localStorage.setItem('mmCoreRedirectState', page);
|
|
|
|
localStorage.setItem('mmCoreRedirectParams', JSON.stringify(params));
|
|
|
|
localStorage.setItem('mmCoreRedirectTime', String(Date.now()));
|
|
|
|
} catch(ex) {}
|
|
|
|
}
|
2018-01-08 13:42:08 +00:00
|
|
|
}
|
2017-10-26 13:03:08 +00:00
|
|
|
}
|