├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── NOTICES.md
├── README-Localized
├── README-de-de.md
├── README-es-es.md
├── README-fr-fr.md
├── README-ja-jp.md
├── README-pt-br.md
├── README-ru-ru.md
├── README-zh-cn.md
└── README-zh-tw.md
├── README.md
├── app
├── .gitignore
├── build.gradle
├── dailyBuild.gradle
├── proguard-rules.pro
└── src
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── microsoft
│ │ │ └── office365
│ │ │ └── connectmicrosoftgraph
│ │ │ ├── AuthenticationCallback.java
│ │ │ ├── AuthenticationManager.java
│ │ │ ├── ConnectActivity.java
│ │ │ ├── Constants.java
│ │ │ ├── MSGraphAPIController.java
│ │ │ ├── MSGraphAPIService.java
│ │ │ ├── RESTHelper.java
│ │ │ ├── SendMailActivity.java
│ │ │ └── vo
│ │ │ ├── BodyVO.java
│ │ │ ├── EmailAddressVO.java
│ │ │ ├── MessageVO.java
│ │ │ ├── MessageWrapper.java
│ │ │ └── ToRecipientsVO.java
│ └── res
│ │ ├── drawable-mdpi
│ │ ├── ic_launcher.png
│ │ └── mail_icon.png
│ │ ├── layout
│ │ ├── activity_connect.xml
│ │ └── activity_send_mail.xml
│ │ ├── menu
│ │ └── send_mail.xml
│ │ ├── values-w820dp
│ │ └── dimens.xml
│ │ └── values
│ │ ├── dimens.xml
│ │ ├── identifiers.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── microsoft
│ └── office365
│ └── connectmicrosoftgraph
│ └── ConnectUnitTests.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── oidclib
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── lnikkila
│ │ └── oidc
│ │ └── ApplicationTest.java
│ └── main
│ ├── AndroidManifest.xml
│ ├── assets
│ └── Roboto-BoldCondensed.ttf
│ ├── java
│ └── com
│ │ └── lnikkila
│ │ └── oidc
│ │ ├── OIDCAccountManager.java
│ │ ├── OIDCRequestManager.java
│ │ ├── authenticator
│ │ ├── Authenticator.java
│ │ ├── AuthenticatorActivity.java
│ │ ├── AuthenticatorService.java
│ │ └── OIDCClientConfigurationActivity.java
│ │ ├── minsdkcompat
│ │ ├── CompatEditText.java
│ │ ├── CompatTextView.java
│ │ └── CompatUri.java
│ │ └── security
│ │ ├── AccountSensitiveDataStorageUtils.java
│ │ ├── SensitiveDataPostApi23.java
│ │ ├── SensitiveDataPreApi23.java
│ │ ├── SensitiveDataUtils.java
│ │ └── UserNotAuthenticatedWrapperException.java
│ └── res
│ ├── color
│ ├── oidc_button_color_selector.xml
│ ├── primary_text_inv_sel.xml
│ ├── primary_text_sel.xml
│ ├── secondary_text_inv_sel.xml
│ └── secondary_text_sel.xml
│ ├── drawable-mdpi
│ ├── ic_account_authenticator.png
│ └── ic_small_account_authenticator.png
│ ├── drawable-xhdpi
│ ├── ic_account_authenticator.png
│ └── ic_small_account_authenticator.png
│ ├── drawable-xxhdpi
│ ├── ic_account_authenticator.png
│ └── ic_small_account_authenticator.png
│ ├── drawable
│ ├── ic_account_authenticator.png
│ └── ic_small_account_authenticator.png
│ ├── layout
│ ├── activity_authentication.xml
│ ├── activity_clientconfiguration.xml
│ ├── spinner_dropdown_item.xml
│ └── spinner_selected_item.xml
│ ├── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── identifiers.xml
│ ├── oidc_clientconf.xml
│ ├── oidc_clientoptions.xml
│ ├── oidc_endpoints.xml
│ ├── strings.xml
│ ├── styles.xml
│ └── theme.xml
│ └── xml
│ └── authenticator.xml
├── readme-images
├── O365-Android-Connect-Constants.png
├── O365-Android-Connect-video_play_icon.png
└── o365-android-microsoft-graph-permissions.png
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.ap_
2 | *.apk
3 | *.class
4 | *.dex
5 | *.iml
6 | *.ipr
7 | *.iws
8 | .DS_Store
9 | .classpath
10 | .gradle
11 | .idea
12 | .project
13 | /.idea/libraries
14 | /.idea/workspace.xml
15 | /build
16 | /captures
17 | /local.properties
18 | Thumbs.db
19 | bin/
20 | build/
21 | gen/
22 | out/
23 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Microsoft. All rights reserved.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/NOTICES.md:
--------------------------------------------------------------------------------
1 | This project includes the following third-party components:
2 |
3 | Android SDK, which is provided by the Android Open Source Project and is used according to terms described in the [Creative Commons 2.5 Attribution License](http://creativecommons.org/licenses/by/2.5/). The Android SDK is available at [http://developer.android.com/sdk/index.html](http://developer.android.com/sdk/index.html).
4 |
5 | OIDCAndroidLib
6 | Copyright (c) 2015, Camilo Montes
7 | Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
8 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
9 |
--------------------------------------------------------------------------------
/README-Localized/README-de-de.md:
--------------------------------------------------------------------------------
1 | # Office 365 Connect-Beispiel für Android unter Verwendung von Microsoft Graph
2 |
3 | 
4 |
5 | [ ](https://www.youtube.com/watch?v=3IQIDFrqhY4 "Klicken Sie, um das Beispiel in Aktion zu sehen.")
6 |
7 | Für die Arbeit mit Office 365-Diensten und -Daten muss jede Android-App zunächst eine Verbindung zu Office 365 herstellen. In diesem Beispiel wird gezeigt, wie die Verbindung zu und dann der Aufruf einer API über Microsoft Graph (wurde zuvor als vereinheitlichte Office 365-API bezeichnet) erfolgt.
8 | > Hinweis: Rufen Sie die Seite [Erste Schritte mit Office 365-APIs](http://dev.office.com/getting-started/office365apis?platform=option-android#setup) auf. Auf dieser wird die Registrierung vereinfacht, damit Sie dieses Beispiel schneller ausführen können.
9 |
10 | ## Geräteanforderungen
11 |
12 | Zum Ausführen des Connect-Beispiels muss das Gerät die folgenden Anforderungen erfüllen:
13 |
14 | * Eine Bildschirmgröße von mindestens 800 x 480 Pixel.
15 | * Android-API-Ebene 15 oder höher.
16 |
17 | ## Voraussetzungen
18 |
19 | Zum Verwenden des Office 365 Connect-Beispiels für Android benötigen Sie Folgendes:
20 |
21 | * [Android Studio](http://developer.android.com/sdk/index.html) Version 1.0 oder höher.
22 | * [Java Development Kit (JDK) 7](http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html).
23 | * Ein Office 365-Konto. Sie können sich für [ein Office 365-Entwicklerabonnement](https://aka.ms/devprogramsignup) registrieren. Dieses umfasst die Ressourcen, die Sie zum Erstellen von Office 365-Apps benötigen.
24 |
25 | > Hinweis: Wenn Sie bereits über ein Abonnement verfügen, gelangen Sie über den vorherigen Link zu einer Seite mit der Meldung *Leider können Sie Ihrem aktuellen Konto diesen Inhalt nicht hinzufügen*. Verwenden Sie in diesem Fall ein Konto aus Ihrem aktuellen Office 365-Abonnement.
26 | * Ein Microsoft Azure-Mandant zum Registrieren Ihrer Anwendung. Von Azure Active Directory werden Identitätsdienste bereitgestellt, die durch Anwendungen für die Authentifizierung und Autorisierung verwendet werden. Hier kann ein Testabonnement erworben werden: [Microsoft Azure](https://account.windowsazure.com/SignUp).
27 |
28 | > Wichtig: Sie müssen zudem sicherstellen, dass Ihr Azure-Abonnement an Ihren Office 365-Mandanten gebunden ist. Rufen Sie dafür den Blogpost [Creating and Managing Multiple Windows Azure Active Directories](http://blogs.technet.com/b/ad/archive/2013/11/08/creating-and-managing-multiple-windows-azure-active-directories.aspx) des Active Directory-Teams auf. Im Abschnitt **Adding a new directory** finden Sie Informationen über die entsprechende Vorgehensweise. Weitere Informationen finden Sie zudem unter [Einrichten Ihrer Office 365-Entwicklungsumgebung](https://msdn.microsoft.com/office/office365/howto/setup-development-environment#bk_CreateAzureSubscription) im Abschnitt **Verknüpfen Ihres Office 365-Kontos mit Azure AD zum Erstellen und Verwalten von Apps**.
29 |
30 | * Eine Client-ID und Umleitungs-URI-Werte einer in Azure registrierten Anwendung. Dieser Beispielanwendung muss die Berechtigung **E-Mails unter einem anderen Benutzernamen senden** für **Microsoft Graph** gewährt werden. [Fügen Sie eine native Clientanwendung in Azure hinzu](https://msdn.microsoft.com/office/office365/HowTo/add-common-consent-manually#bk_RegisterNativeApp), und [gewähren Sie ihr die entsprechenden Berechtigungen](https://github.com/OfficeDev/O365-Android-Microsoft-Graph-Connect/wiki/Grant-permissions-to-the-Connect-application-in-Azure).
31 |
32 | ## Öffnen des Beispiels mithilfe von Android Studio
33 |
34 | 1. Installieren Sie [Android Studio](http://developer.android.com/sdk/index.html), und fügen Sie gemäß den [Anleitungen](http://developer.android.com/sdk/installing/adding-packages.html) auf „developer.android.com“ die Android SDK-Pakete hinzu.
35 | 2. Laden Sie dieses Beispiel herunter, oder klonen Sie es.
36 | 3. Starten Sie Android-Studio.
37 | 1. Schließen Sie alle möglicherweise geöffneten Projekte, und wählen Sie dann **Vorhandenes Android Studio-Projekt öffnen** aus.
38 | 2. Navigieren Sie zum lokalen Repository, und wählen Sie das Projekt „O365-Android-Microsoft-Graph-Connect“ aus. Klicken Sie auf **OK**.
39 |
40 | > Hinweis: In Android Studio wird möglicherweise ein Dialogfeld angezeigt, in dem Sie gefragt werden, ob Sie den Gradle-Wrapper verwenden möchten. Klicken Sie auf **OK**.
41 | >
42 | > **Frameworks erkannt****Android-Support-Repository**
43 | 4. Öffnen Sie die Datei „Constants.java“.
44 | 1. Suchen Sie nach der Konstante „CLIENT_ID“, und legen Sie ihren Wert „String“ entsprechend der Client-ID fest, die Sie in Azure Active Directory registriert haben.
45 | 2. Suchen Sie nach der Konstante „REDIRECT_URI“, und legen Sie ihren Wert „String“ entsprechend dem Umleitungs-URI fest, den Sie in Azure Active Directory registriert haben.
46 | 
47 |
48 | > Hinweis: Wenn Sie weder über „CLIENT_ID“- noch über „REDIRECT_URI“-Werte verfügen, [müssen Sie eine native Clientanwendung in Azure hinzufügen](https://msdn.microsoft.com/de-de/library/azure/dn132599.aspx#BKMK_Adding) und die Werte „CLIENT_ID“ und „REDIRECT_URI“ beachten.
49 |
50 | Nach dem Einrichten des Connect-Beispiels können Sie es auf einem Emulator oder Gerät ausführen. Wählen Sie ein Gerät mit API-Ebene 15 oder höher aus dem Dialogfeld **Gerät auswählen** aus.
51 |
52 | Weitere Informationen über das Beispiel finden Sie unter [Aufrufen von Microsoft Graph in einer Android-App](https://graph.microsoft.io/de-de/docs/platform/android).
53 |
54 | ## Fragen und Kommentare
55 |
56 | Wir schätzen Ihr Feedback hinsichtlich des Office 365 Android Connect-Projekts. Sie können uns Ihre Fragen und Vorschläge über den Abschnitt [Probleme](https://github.com/OfficeDev/O365-Android-Microsoft-Graph-Connect/issues) dieses Repositorys senden.
57 |
58 | Allgemeine Fragen über die Office 365-Entwicklung sollten in [Stack Overflow](http://stackoverflow.com/questions/tagged/Office365+API) gepostet werden. Stellen Sie sicher, dass Ihre Fragen oder Kommentare mit [Office365] und [API] markiert sind.
59 |
60 | ## Nächste Schritte
61 |
62 | In diesem Beispiel werden die Grundlagen für das Funktionieren Ihrer Apps mit Office 365 gezeigt. Mithilfe von Office 365-APIs können Ihre Apps viele weitere Aktionen vornehmen wie das Unterstützen Ihrer Benutzer bei der Verwaltung ihrer täglichen Arbeit mit dem Kalender, das Auffinden der benötigten Informationen in allen in OneDrive gespeicherten Dateien oder das Auffinden der gewünschten Person in ihrer Liste der Kontakte. Weitere interessante Informationen finden Sie unter [Office 365 APIs-Startprojekt für Android](https://github.com/officedev/O365-Android-Start/). Diese werden unserer Ansicht nach Ihre Ideen bereichern.
63 |
64 | ## Zusätzliche Ressourcen
65 |
66 | * [Office 365 APIs-Plattformübersicht](https://msdn.microsoft.com/office/office365/howto/platform-development-overview)
67 | * [Erste Schritte mit Office 365-APIs](http://dev.office.com/getting-started/office365apis)
68 | * [Übersicht zu Office 365 Microsoft Graph](http://graph.microsoft.io)
69 | * [Office 365 SDK für Android](https://github.com/OfficeDev/Office-365-SDK-for-Android)
70 | * [Office 365 APIs-Startprojekt und -Codebeispiele](https://msdn.microsoft.com/office/office365/howto/starter-projects-and-code-samples)
71 | * [Office 365 Android Microsoft Graph-Ausschnitte](https://github.com/OfficeDev/O365-Android-Microsoft-Graph-Snippets)
72 | * [Office 365 APIs-Startprojekt für Android](https://github.com/OfficeDev/O365-Android-Start)
73 | * [Office 365 Profile-Beispiel für Android](https://github.com/OfficeDev/O365-Android-Profile)
74 |
75 |
76 | ## Copyright
77 | Copyright (c) 2015 Microsoft. Alle Rechte vorbehalten.
78 |
--------------------------------------------------------------------------------
/README-Localized/README-es-es.md:
--------------------------------------------------------------------------------
1 | # Ejemplo Connect de Office 365 para Android con Microsoft Graph
2 |
3 | 
4 |
5 | [ ](https://www.youtube.com/watch?v=3IQIDFrqhY4 "Haga clic para ver el ejemplo en funcionamiento")
6 |
7 | Conectarse a Office 365 es el primer paso que debe realizar cada aplicación Android para empezar a trabajar con los datos y servicios de Office 365. Este ejemplo muestra cómo conectar y cómo llamar después a una API a través de Microsoft Graph (anteriormente denominada API unificada de Office 365).
8 | > Nota: Consulte [Introducción a las API de Office 365](http://dev.office.com/getting-started/office365apis?platform=option-android#setup), que simplifica el registro para que este ejemplo se ejecute más rápidamente.
9 |
10 | ## Requisitos del dispositivo
11 |
12 | Para ejecutar el ejemplo Connect, el dispositivo debe cumplir los siguientes requisitos:
13 |
14 | * Una pantalla de tamaño de 800 x 480 o superior.
15 | * Nivel de API de Android 15 o superior.
16 |
17 | ## Requisitos previos
18 |
19 | Para usar el ejemplo Connect de Office 365 para Android, necesita lo siguiente:
20 |
21 | * [Android Studio](http://developer.android.com/sdk/index.html) versión 1.0 o posterior.
22 | * [Kit de desarrollo Java (JDK) 7](http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html).
23 | * Una cuenta de Office 365. Puede registrarse en [una suscripción a Office 365 Developer](https://aka.ms/devprogramsignup), que incluye los recursos que necesita para comenzar a crear aplicaciones de Office 365.
24 |
25 | > Nota: Si ya dispone de una suscripción, el vínculo anterior le dirige a una página con el mensaje *No se puede agregar a su cuenta actual*. En ese caso, use una cuenta de su suscripción actual a Office 365.
26 | * Un inquilino de Microsoft Azure para registrar la aplicación. Azure Active Directory proporciona servicios de identidad que las aplicaciones usan para autenticación y autorización. Puede adquirir una suscripción de prueba aquí: [Microsoft Azure](https://account.windowsazure.com/SignUp).
27 |
28 | > Importante: También necesitará asegurarse de que su suscripción a Azure esté enlazada a su inquilino de Office 365. Para ello, consulte la publicación del blog del equipo de Active Directory, [Crear y administrar varios directorios de Windows Azure Active Directory](http://blogs.technet.com/b/ad/archive/2013/11/08/creating-and-managing-multiple-windows-azure-active-directories.aspx). La sección **Agregar un nuevo directorio** le explicará cómo hacerlo. Para obtener más información, también puede consultar [Configurar el entorno de desarrollo de Office 365](https://msdn.microsoft.com/office/office365/howto/setup-development-environment#bk_CreateAzureSubscription) y la sección **Asociar su cuenta de Office 365 con Azure AD para crear y administrar aplicaciones**.
29 |
30 | * Los valores de identificador de cliente y URI de redireccionamiento de una aplicación registrada en Azure. A esta aplicación de ejemplo se le debe conceder el permiso **Enviar correo como usuario** para **Microsoft Graph**. [Agregar una aplicación de cliente nativa en Azure](https://msdn.microsoft.com/office/office365/HowTo/add-common-consent-manually#bk_RegisterNativeApp) y [concederle los permisos adecuados](https://github.com/OfficeDev/O365-Android-Microsoft-Graph-Connect/wiki/Grant-permissions-to-the-Connect-application-in-Azure).
31 |
32 | ## Abrir el ejemplo con Android Studio
33 |
34 | 1. Instale [Android Studio](http://developer.android.com/sdk/index.html) y agregue los paquetes del SDK de Android según las [instrucciones](http://developer.android.com/sdk/installing/adding-packages.html) de developer.android.com.
35 | 2. Descargue o clone este ejemplo.
36 | 3. Inicie Android Studio.
37 | 1. Cierre todos los proyectos que tenga abiertos y, a continuación, elija **Open an existing Android Studio project** (Abrir un proyecto existente de Android Studio).
38 | 2. Examine su repositorio local y elija el proyecto O365-Android-Microsoft-Graph-Connect. Haga clic en **OK** (Aceptar).
39 |
40 | > Nota: Android Studio podría mostrar un cuadro de diálogo preguntándole si desea usar el contenedor Gradle. Haga clic en **OK** (Aceptar).
41 | >
42 | > **Frameworks detected****Android Support Repository**
43 | 4. Abra el archivo Constants.java.
44 | 1. Busque la constante CLIENT_ID y establezca el mismo valor de cadena que el valor del identificador de cliente que registró en Azure Active Directory.
45 | 2. Busque la constante REDIRECT_URI y establezca el mismo valor de cadena que el valor del URI de redireccionamiento que registró en Azure Active Directory. 
46 |
47 | > Nota: Si no dispone de los valores CLIENT_ID y REDIRECT_URI, [agregue una aplicación de cliente nativa en Azure](https://msdn.microsoft.com/es-es/library/azure/dn132599.aspx#BKMK_Adding) y anote los valores CLIENT_ID y REDIRECT_URI.
48 |
49 | Una vez creado el ejemplo Connect, puede ejecutarlo en un emulador o en un dispositivo. Elija un dispositivo con un nivel de API 15 o superior desde el cuadro de diálogo **Choose device** (Elegir dispositivo).
50 |
51 | Para obtener más información acerca del ejemplo, consulte [Llamar a Microsoft Graph en una aplicación Android](https://graph.microsoft.io/es-es/docs/platform/android).
52 |
53 | ## Preguntas y comentarios
54 |
55 | Nos encantaría recibir sus comentarios acerca del ejemplo Connect de Android de Office 365. Puede enviarnos sus preguntas y sugerencias a través de la sección [Problemas](https://github.com/OfficeDev/O365-Android-Microsoft-Graph-Connect/issues) de este repositorio.
56 |
57 | Las preguntas generales sobre desarrollo en Office 365 deben publicarse en [Stack Overflow](http://stackoverflow.com/questions/tagged/Office365+API). Asegúrese de que sus preguntas o comentarios se etiquetan con [Office365] y [API].
58 |
59 | ## Pasos siguientes
60 |
61 | Este ejemplo muestra solo los elementos esenciales que las aplicaciones necesitan para funcionar en Office 365. Sus aplicaciones pueden hacer muchas más cosas con las API de Office 365, como ayudar a sus usuarios a administrar su día de trabajo con el calendario, encontrar la información que necesitan en todos los archivos que almacenan en OneDrive o encontrar la persona exacta que necesitan de la lista de contactos. Tenemos más información que compartir en [Proyecto de inicio de las API de Office 365 para Android](https://github.com/officedev/O365-Android-Start/). Creemos que puede ayudarle a alimentar sus ideas.
62 |
63 | ## Recursos adicionales
64 |
65 | * [Información general sobre la plataforma de las API de Office 365](https://msdn.microsoft.com/office/office365/howto/platform-development-overview)
66 | * [Introducción a las API de Office 365](http://dev.office.com/getting-started/office365apis)
67 | * [Información general de Microsoft Graph de Office 365](http://graph.microsoft.io)
68 | * [SDK de Office 365 para Android](https://github.com/OfficeDev/Office-365-SDK-for-Android)
69 | * [Proyectos de inicio de las API de Office 365 y ejemplos de código](https://msdn.microsoft.com/office/office365/howto/starter-projects-and-code-samples)
70 | * [Fragmentos de código de Microsoft Graph de Office 365 para Android](https://github.com/OfficeDev/O365-Android-Microsoft-Graph-Snippets)
71 | * [Proyecto de inicio de las API de Office 365 para Android](https://github.com/OfficeDev/O365-Android-Start)
72 | * [Ejemplo de perfil de Office 365 para Android](https://github.com/OfficeDev/O365-Android-Profile)
73 |
74 |
75 | ## Copyright
76 | Copyright (c) 2015 Microsoft. Todos los derechos reservados.
77 |
--------------------------------------------------------------------------------
/README-Localized/README-fr-fr.md:
--------------------------------------------------------------------------------
1 | # Exemple de connexion d’Android à Office 365 avec Microsoft Graph
2 |
3 | 
4 |
5 |
6 | [ ](https://www.youtube.com/watch?v=3IQIDFrqhY4 "Cliquez ici pour voir l’exemple en action")
7 |
8 | La connexion à Office 365 est la première étape que chaque application Android doit suivre pour commencer à travailler avec les services et les données Office 365. Cet exemple explique comment connecter, puis appeler une API via Microsoft Graph (anciennement appelé API unifiée Office 365).
9 | > Remarque : consultez la page relative à la [prise en main des API Office 365](http://dev.office.com/getting-started/office365apis?platform=option-android#setup) pour enregistrer plus facilement votre application et exécuter plus rapidement cet exemple.
10 |
11 | ## Configuration requise de l’appareil
12 |
13 | Pour exécuter l’exemple de connexion, votre appareil doit respecter les exigences suivantes :
14 |
15 | * Un écran de 800 x 480, ou plus.
16 | * Une API Android de niveau 15, ou supérieur.
17 |
18 | ## Conditions préalables
19 |
20 | Pour utiliser l’exemple de connexion d’Android à Office 365, vous devez disposer des éléments suivants :
21 |
22 | * [Android Studio](http://developer.android.com/sdk/index.html) version 1.0 ou ultérieure.
23 | * [Kit de développement Java (JDK) 7](http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html).
24 | * Un compte Office 365. Vous pouvez vous inscrire à [Office 365 Developer](https://aka.ms/devprogramsignup) pour accéder aux ressources dont vous avez besoin pour commencer à créer des applications Office 365.
25 |
26 | > Remarque : si vous avez déjà un abonnement, le lien précédent vous renvoie vers une page avec le message suivant : *Désolé, vous ne pouvez pas ajouter ceci à votre compte existant*. Dans ce cas, utilisez un compte lié à votre abonnement Office 365 existant.
27 | * Un client Microsoft Azure pour enregistrer votre application. Azure Active Directory fournit des services d’identité que les applications utilisent à des fins d’authentification et d’autorisation. Un abonnement d’évaluation peut être demandé ici : [Microsoft Azure](https://account.windowsazure.com/SignUp).
28 |
29 | > Important : vous devrez également vous assurer que votre abonnement Azure est lié à votre client Office 365. Pour cela, consultez le billet du blog de l’équipe d’Active Directory relatif à la [création et la gestion de plusieurs fenêtres dans les répertoires Azure Active Directory](http://blogs.technet.com/b/ad/archive/2013/11/08/creating-and-managing-multiple-windows-azure-active-directories.aspx). La section sur l’**ajout d’un nouveau répertoire** vous explique comment procéder. Pour en savoir plus, vous pouvez également consulter la rubrique relative à la [configuration de votre environnement de développement Office 365](https://msdn.microsoft.com/office/office365/howto/setup-development-environment#bk_CreateAzureSubscription) et la section sur l’**association de votre compte Office 365 à Azure Active Directory pour créer et gérer des applications**.
30 |
31 | * Un ID client et les valeurs URI de redirection d’une application enregistrée dans Azure. Cet exemple d’application doit obtenir l’autorisation **Envoyer un courrier électronique en tant qu’utilisateur** pour **Microsoft Graph**. [Ajoutez une application cliente native dans Azure](https://msdn.microsoft.com/office/office365/HowTo/add-common-consent-manually#bk_RegisterNativeApp) et [accordez-lui les autorisations appropriées](https://github.com/OfficeDev/O365-Android-Microsoft-Graph-Connect/wiki/Grant-permissions-to-the-Connect-application-in-Azure).
32 |
33 | ## Ouverture de l’exemple avec Android Studio
34 |
35 | 1. Installez [Android Studio](http://developer.android.com/sdk/index.html) et ajoutez les packages SDK Android en fonction des [instructions](http://developer.android.com/sdk/installing/adding-packages.html) données sur developer.android.com.
36 | 2. Téléchargez ou clonez cet exemple.
37 | 3. Démarrez Android Studio.
38 | 1. Fermez tous les projets ouverts, puis cliquez sur **Ouvrir un projet Android Studio existant**.
39 | 2. Ouvrez votre référentiel local et sélectionnez le projet O365-Android-Microsoft-Graph-Connect. Cliquez sur **OK**.
40 |
41 | > Remarque : Android Studio peut afficher une boîte de dialogue pour vous demander si vous souhaitez utiliser le wrapper Gradle. Cliquez sur **OK**.
42 | >
43 | > **Infrastructures détectées****Référentiel de support Android**
44 | 4. Ouvrez le fichier Constants.java.
45 | 1. Recherchez la constante CLIENT_ID et définissez sa valeur de chaîne sur l’ID du client que vous avez enregistré dans Azure Active Directory.
46 | 2. Recherchez la constante REDIRECT_URI et définissez sa valeur de chaîne sur l’URI de redirection que vous avez enregistré dans Azure Active Directory.
47 | 
48 |
49 | > Remarque : si vous ne connaissez pas les valeurs de CLIENT_ID et de REDIRECT_URI, [ajoutez une application cliente native dans Azure](https://msdn.microsoft.com/fr-fr/library/azure/dn132599.aspx#BKMK_Adding) pour les noter.
50 |
51 | Une fois l’exemple de connexion créé, vous pouvez l’exécuter sur un émulateur ou un appareil. Choisissez un appareil avec une API de niveau 15 ou supérieur dans la boîte de dialogue **Choisir un appareil**.
52 |
53 | Pour en savoir plus sur cet exemple, consultez la rubrique relative à l’[appel de Microsoft Graph dans une application Android](https://graph.microsoft.io/fr-fr/docs/platform/android).
54 |
55 | ## Questions et commentaires
56 |
57 | Nous serions ravis de connaître votre opinion sur le projet de connexion d’Android à Office 365. Vous pouvez nous faire part de vos questions et suggestions dans la rubrique [Problèmes](https://github.com/OfficeDev/O365-Android-Microsoft-Graph-Connect/issues) de ce référentiel.
58 |
59 | Si vous avez des questions sur le développement d’Office 365, envoyez-les sur [Stack Overflow](http://stackoverflow.com/questions/tagged/Office365+API). Posez vos questions avec les tags [API] et [Office 365].
60 |
61 | ## Étapes suivantes
62 |
63 | Cet exemple montre uniquement les conditions minimales que vos applications doivent remplir pour fonctionner avec Office 365. Vos applications peuvent faire tellement de choses grâce aux API Office 365 : aider vos utilisateurs à organiser leur semaine avec le calendrier, rechercher les informations dont ils ont besoin dans tous les fichiers stockés dans OneDrive, ou rechercher la bonne personne dans leur liste de contacts. Nous avons bien d’autres choses à vous proposer dans le [Projet de lancement des API Office 365 pour Android](https://github.com/officedev/O365-Android-Start/). Nous pensons qu’il peut vous aider à nourrir votre créativité.
64 |
65 | ## Ressources supplémentaires
66 |
67 | * [Présentation de la plateforme des API Office 365](https://msdn.microsoft.com/office/office365/howto/platform-development-overview)
68 | * [Prise en main des API Office 365](http://dev.office.com/getting-started/office365apis)
69 | * [Présentation de Microsoft Graph d’Office 365](http://graph.microsoft.io)
70 | * [Kit de développement logiciel (SDK) Office 365 pour Android](https://github.com/OfficeDev/Office-365-SDK-for-Android)
71 | * [Exemples de code et projets de lancement pour les API Office 365](https://msdn.microsoft.com/office/office365/howto/starter-projects-and-code-samples)
72 | * [Extraits de code Android Microsoft Graph Office 365](https://github.com/OfficeDev/O365-Android-Microsoft-Graph-Snippets)
73 | * [Projet de lancement des API Office 365 pour Android](https://github.com/OfficeDev/O365-Android-Start)
74 | * [Exemple de profil Office 365 pour Android](https://github.com/OfficeDev/O365-Android-Profile)
75 |
76 |
77 | ## Copyright
78 | Copyright (c) 2015 Microsoft. Tous droits réservés.
79 |
--------------------------------------------------------------------------------
/README-Localized/README-ja-jp.md:
--------------------------------------------------------------------------------
1 | # Microsoft Graph を使った Android 用 Office 365 Connect サンプル
2 |
3 | 
4 |
5 | [ ](https://www.youtube.com/watch?v=3IQIDFrqhY4 "活用できるサンプルを確認するにはこちらをクリックしてください")
6 |
7 | 各 Android アプリで Office 365 のサービスとデータの操作を開始するため、最初に Office 365 に接続する必要があります。このサンプルでは、Microsoft Graph (以前は Office 365 統合 API と呼ばれていた) を介して、1 つの API に接続して呼び出す方法を示します。
8 | > メモ: このサンプルをより迅速に実行するため、「[Office 365 API を使う](http://dev.office.com/getting-started/office365apis?platform=option-android#setup)」ページに記載された登録の簡略化をお試しください。
9 |
10 | ## デバイスの要件
11 |
12 | Connect のサンプルを実行するには、デバイスが次の要件を満たしている必要があります。
13 |
14 | * 画面のサイズが 800 x 480 以上である。
15 | * Android の API レベルが 15 以上である。
16 |
17 | ## 前提条件
18 |
19 | Android 用 Office 365 Connect サンプルを使うには次が必要です。
20 |
21 | *[Android Studio](http://developer.android.com/sdk/index.html) バージョン 1.0 以降。
22 | * [Java 開発キット (JDK) 7](http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html)。
23 | * Office 365 アカウント。Office 365 アプリのビルドを開始するために必要なリソースを含む [Office 365 Developer サブスクリプション](https://aka.ms/devprogramsignup) にサインアップできます。
24 |
25 | > メモ: サブスクリプションをすでにお持ちの場合、上記のリンクをクリックすると、「*申し訳ございません。現在のアカウントに追加できません*」というメッセージが表示されるページに移動します。その場合は、現在使っている Office 365 サブスクリプションのアカウントをご利用いただけます。
26 | * アプリケーションを登録する Microsoft Azure テナント。Azure Active Directory は、アプリケーションが認証と承認に使用する ID サービスを提供します。ここでは、試用版サブスクリプションを取得できます。 [Microsoft Azure](https://account.windowsazure.com/SignUp)。
27 |
28 | > 重要: Azure サブスクリプションが Office 365 テナントにバインドされていることを確認する必要もあります。確認する方法については、Active Directory チームのブログ投稿「[複数の Windows Azure Active Directory を作成して管理する](http://blogs.technet.com/b/ad/archive/2013/11/08/creating-and-managing-multiple-windows-azure-active-directories.aspx)」をご覧ください。「**新しいディレクトリを追加する**」セクションで、この方法を説明しています。また、詳しくは、「[Office 365 開発環境のセットアップ](https://msdn.microsoft.com/office/office365/howto/setup-development-environment#bk_CreateAzureSubscription)」と「**Office 365 アカウントを Azure AD と関連付けて、アプリを作成して管理する**」のセクションをご覧ください。
29 |
30 | * Azure に登録されたアプリケーションのクライアント ID とリダイレクト URI の値。このサンプル アプリケーションには、**Microsoft Graph** の**ユーザーとしてメールを送信する**アクセス許可を付与する必要があります。[Azure にネイティブ クライアント アプリケーションを追加](https://msdn.microsoft.com/office/office365/HowTo/add-common-consent-manually#bk_RegisterNativeApp)し、[適切なアクセス許可を付与](https://github.com/OfficeDev/O365-Android-Microsoft-Graph-Connect/wiki/Grant-permissions-to-the-Connect-application-in-Azure)します。
31 |
32 | ## Android Studio を使ってサンプルを開く
33 |
34 | 1. developer.android.com の[指示](http://developer.android.com/sdk/installing/adding-packages.html)に従って、[Android Studio](http://developer.android.com/sdk/index.html) をインストールし、Android SDK パッケージを追加します。
35 | 2. このサンプルをダウンロードするか、複製を作成します。
36 | 3. Android Studio を起動します。
37 | 1. 開いているプロジェクトをすべて閉じ、**[既存のAndroid Studio プロジェクトを開く]** を選択します。
38 | 2. ローカル リポジトリを参照し、O365-Android-Microsoft-Graph-Connect プロジェクトを選択します。**[OK]** をクリックします。
39 |
40 | > メモ: Android Studio では、Gradle ラッパーを使うかどうかを尋ねるダイアログが表示されることがあります。**[OK]** をクリックします。
41 | >
42 | > **検出されたフレームワーク****Android サポート リポジトリ**
43 | 4. Constants.java ファイルを開きます。
44 | 1. CLIENT_ID 定数を検索して、その String 値を Azure Active Directory に登録されているクライアント ID と同じ値に設定します。
45 | 2. REDIRECT_URI 定数を検索して、その String 値を Azure Active Directory に登録されているリダイレクト URI と同じ値に設定します。
46 | 
47 |
48 | > メモ: CLIENT_ID と REDIRECT_URI の値がない場合は、[ネイティブ クライアント アプリケーションを Azure に追加](https://msdn.microsoft.com/ja-jp/library/azure/dn132599.aspx#BKMK_Adding)し、CLIENT_ID と REDIRECT_URI を書き留めます。
49 |
50 | Connect のサンプルをビルドしたら、エミュレーターやデバイス上で実行できます。**[デバイスの選択]** ダイアログから API レベル 15 以上のデバイスを選びます。
51 |
52 | サンプルについて詳しくは、「[Android アプリで Microsoft Graph を呼び出す](https://graph.microsoft.io/ja-jp/docs/platform/android)」をご覧ください。
53 |
54 | ## 質問とコメント
55 |
56 | Office 365 Android Connect プロジェクトに関するフィードバックをお寄せください。質問や提案につきましては、このリポジトリの「[問題](https://github.com/OfficeDev/O365-Android-Microsoft-Graph-Connect/issues)」セクションで送信できます。
57 |
58 | Office 365 開発全般の質問につきましては、「[スタック オーバーフロー](http://stackoverflow.com/questions/tagged/Office365+API)」に投稿してください。質問やコメントには、必ず [Office365] と [API] のタグを付けてください。
59 |
60 | ## 次の手順
61 |
62 | このサンプルでは、アプリが Office 365 を使用して操作する必要がある重要項目のみを示しています。Office 365 API を使って、アプリでできることはさらにあります。たとえば、ユーザーが予定表で作業日を管理できるようにする、ユーザーが OneDrive に保存したすべてのファイルで必要な情報を検索する、連絡先のリストからユーザーが必要とする人を正確に見つけるなどです。「[Android 用 Office 365 API スタート プロジェクト](https://github.com/officedev/O365-Android-Start/)」でさらに説明しています。より良いアイデアの助けになればと思います。
63 |
64 | ## その他の技術情報
65 |
66 | * [Office 365 API プラットフォームの概要](https://msdn.microsoft.com/office/office365/howto/platform-development-overview)
67 | * [Office 365 API を使う](http://dev.office.com/getting-started/office365apis)
68 | * [Office 365 Microsoft Graph の概要](http://graph.microsoft.io)
69 | * [Office 365 SDK for Android](https://github.com/OfficeDev/Office-365-SDK-for-Android)
70 | * [Office 365 API スタート プロジェクトとコード サンプル](https://msdn.microsoft.com/office/office365/howto/starter-projects-and-code-samples)
71 | * [Office 365 Android Microsoft Graph のスニペット](https://github.com/OfficeDev/O365-Android-Microsoft-Graph-Snippets)
72 | * [Android 用 Office 365 API スタート プロジェクト](https://github.com/OfficeDev/O365-Android-Start)
73 | * [Android 用 Office 365 プロファイル サンプル](https://github.com/OfficeDev/O365-Android-Profile)
74 |
75 |
76 | ## 著作権
77 | Copyright (c) 2015 Microsoft.All rights reserved.
78 |
--------------------------------------------------------------------------------
/README-Localized/README-pt-br.md:
--------------------------------------------------------------------------------
1 | # Exemplo de conexão com o Office 365 para Android usando o Microsoft Graph
2 |
3 | 
4 |
5 | [ ](https://www.youtube.com/watch?v=3IQIDFrqhY4 "Clique no exemplo para vê-lo em ação")
6 |
7 | A primeira etapa para que os aplicativos Android comecem a funcionar com dados e serviços do Office 365 é estabelecer uma conexão com essa plataforma. Este exemplo mostra como conectar e chamar uma única API através do Microsoft Graph (antiga API unificada do Office 365).
8 | > Observação: experimente a página [Introdução às APIs do Office 365](http://dev.office.com/getting-started/office365apis?platform=option-android#setup), que simplifica o registro para que você possa executar esse exemplo com mais rapidez.
9 |
10 | ## Requisitos do dispositivo
11 |
12 | Para executar o exemplo de conexão, o dispositivo deve atender aos seguintes requisitos:
13 |
14 | * Uma tela de tamanho 800 x 480 ou maior.
15 | * API Android nível 15 ou superior.
16 |
17 | ## Pré-requisitos
18 |
19 | Para usar o exemplo de conexão com o Office 365 para Android, é necessário o seguinte:
20 |
21 | * [Android Studio](http://developer.android.com/sdk/index.html) versão 1.0 ou posterior.
22 | * [JDK (Java Development Kit) 7](http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html).
23 | * Uma conta do Office 365. Inscreva-se para uma [Assinatura de Desenvolvedor do Office 365](https://aka.ms/devprogramsignup), que inclui os recursos necessários para começar a criação de aplicativos do Office 365.
24 |
25 | > Observação: caso já tenha uma assinatura, o link anterior direciona você para uma página com a mensagem *Não é possível adicioná-la à sua conta atual*. Nesse caso, use uma conta de sua assinatura atual do Office 365.
26 | * Um locatário do Microsoft Azure para registrar o seu aplicativo. O Azure Active Directory fornece serviços de identidade que os aplicativos usam para autenticação e autorização. Você pode adquirir uma assinatura de avaliação aqui: [Microsoft Azure](https://account.windowsazure.com/SignUp).
27 |
28 | > Importante: você também deve assegurar que a assinatura do Azure esteja vinculada ao locatário do Office 365. Para fazer isso, confira a postagem de blog da equipe do Active Directory, [Criando e gerenciando vários Active Directories do Microsoft Azure](http://blogs.technet.com/b/ad/archive/2013/11/08/creating-and-managing-multiple-windows-azure-active-directories.aspx). A seção **Adicionando um novo diretório** explica como fazer isso. Para saber mais, confira o artigo [Configurar o ambiente de desenvolvimento do Office 365](https://msdn.microsoft.com/office/office365/howto/setup-development-environment#bk_CreateAzureSubscription) e a seção **Associar uma conta do Office 365 ao AD do Azure para criar e gerenciar aplicativos**.
29 |
30 | * Valores de uma ID do cliente e de um URI de redirecionamento de um aplicativo registrado no Azure. Esse exemplo de aplicativo deve ter a permissão **Enviar email como usuário** concedida para o **Microsoft Graph**. Para isso, [adicione um aplicativo cliente nativo no Microsoft Azure](https://msdn.microsoft.com/office/office365/HowTo/add-common-consent-manually#bk_RegisterNativeApp) e [conceda as permissões adequadas](https://github.com/OfficeDev/O365-Android-Microsoft-Graph-Connect/wiki/Grant-permissions-to-the-Connect-application-in-Azure).
31 |
32 | ## Abra o exemplo usando o Android Studio
33 |
34 | 1. Instale o [Android Studio](http://developer.android.com/sdk/index.html) e adicione os pacotes do SDK do Android de acordo com as [instruções](http://developer.android.com/sdk/installing/adding-packages.html) na página developer.android.com.
35 | 2. Baixe ou clone esse exemplo.
36 | 3. Inicie o Android Studio.
37 | 1. Feche todos os projetos abertos e escolha **Abrir um projeto existente do Android Studio**.
38 | 2. Navegue até o repositório local e escolha o projeto O365-Android-Microsoft-Graph-Connect. Clique em **OK**.
39 |
40 | > Observação: O Android Studio pode exibir uma caixa de diálogo perguntando se você deseja usar o wrapper Gradle. Clique em **OK**.
41 | >
42 | > **Estruturas detectadas****Repositório de suporte do Android**
43 | 4. Abra o arquivo Constants.java.
44 | 1. Localize a constante CLIENT_ID e defina o respectivo valor da cadeia de caracteres igual a ID do cliente registrada no Azure Active Directory.
45 | 2. Localize a constante REDIRECT_URI e defina o respectivo valor da cadeia de caracteres igual à URI de redirecionamento registrada no Azure Active Directory.
46 | 
47 |
48 | > Observação: caso não tenha os valores CLIENT_ID e REDIRECT_URI, [adicione um aplicativo cliente nativo no Azure](https://msdn.microsoft.com/pt-br/library/azure/dn132599.aspx#BKMK_Adding) e anote os valores do CLIENT_ID e do REDIRECT_URI.
49 |
50 | Depois de criar o exemplo de conexão, você pode executá-lo em um emulador ou dispositivo. Escolha um dispositivo com API de nível 15 ou superior na caixa de diálogo **Escolher dispositivo**.
51 |
52 | Para saber mais sobre o exemplo, confira o artigo [Chamar o Microsoft Graph em um aplicativo Android](https://graph.microsoft.io/pt-br/docs/platform/android).
53 |
54 | ## Perguntas e comentários
55 |
56 | Gostaríamos de saber sua opinião sobre o projeto de conexão com o Office 365 para Android. Você pode enviar perguntas e sugestões na seção [Problemas](https://github.com/OfficeDev/O365-Android-Microsoft-Graph-Connect/issues) deste repositório.
57 |
58 | Faça a postagem de perguntas sobre desenvolvimento do Office 365 em geral na página do [Stack Overflow](http://stackoverflow.com/questions/tagged/Office365+API). Não deixe de marcar as perguntas ou comentários com [Office365] e [API].
59 |
60 | ## Próximas etapas
61 |
62 | Este exemplo mostra apenas os conceitos básicos necessários para que os aplicativos funcionem com o Office 365. O aplicativo pode fazer muito mais usando as APIs do Office 365, como ajudar os usuários a gerenciar os dias úteis com o calendário, localizar apenas as informações necessárias em todos os arquivos armazenados no OneDrive ou localizar uma pessoa específica na lista de contatos. Temos mais recursos para compartilhar com você no [Projeto inicial de APIs do Office 365 para Android](https://github.com/officedev/O365-Android-Start/). Esse conteúdo pode ajudar a fomentar suas ideias.
63 |
64 | ## Recursos adicionais
65 |
66 | * [Visão geral da plataforma de APIs do Office 365](https://msdn.microsoft.com/office/office365/howto/platform-development-overview)
67 | * [Introdução às APIs do Office 365](http://dev.office.com/getting-started/office365apis)
68 | * [Visão geral do Microsoft Graph do Office 365](http://graph.microsoft.io)
69 | * [SDK do Office 365 para Android](https://github.com/OfficeDev/Office-365-SDK-for-Android)
70 | * [Exemplos de código e projetos iniciais de APIs do Office 365](https://msdn.microsoft.com/office/office365/howto/starter-projects-and-code-samples)
71 | * [Trechos do Microsoft Graph do Office 365 para Android](https://github.com/OfficeDev/O365-Android-Microsoft-Graph-Snippets)
72 | * [Projeto inicial de APIs do Office 365 para Android](https://github.com/OfficeDev/O365-Android-Start)
73 | * [Exemplo de perfil do Office 365 para Android](https://github.com/OfficeDev/O365-Android-Profile)
74 |
75 |
76 | ## Direitos autorais
77 | Copyright © 2015 Microsoft. Todos os direitos reservados.
78 |
--------------------------------------------------------------------------------
/README-Localized/README-ru-ru.md:
--------------------------------------------------------------------------------
1 | # Пример приложения Android, подключающегося к Office 365 и использующего Microsoft Graph
2 |
3 | 
4 |
5 | [ ](https://www.youtube.com/watch?v=3IQIDFrqhY4 "Щелкните, чтобы просмотреть этот пример в действии")
6 |
7 | Подключение к Office 365 — это первый шаг, который должно выполнить каждое приложение для Android, чтобы начать работу со службами и данными Office 365. В этом примере показано, как подключить, а затем вызвать один API с помощью Microsoft Graph (прежнее название — единый API Office 365).
8 | > Примечание. Перейдите на страницу [Начало работы с API Office 365](http://dev.office.com/getting-started/office365apis?platform=option-android#setup) для упрощенной регистрации, чтобы ускорить запуск этого примера.
9 |
10 | ## Требования к устройству
11 |
12 | Для запуска приложения для подключения устройство должно соответствовать следующим требованиям:
13 |
14 | * размер экрана должен составлять не менее 800 x 480;
15 | * должен использоваться API Android уровня 15 или более высокого.
16 |
17 | ## Предварительные требования
18 |
19 | Чтобы воспользоваться примером приложения Android, подключающегося к Office 365, требуются перечисленные ниже компоненты.
20 |
21 | * [Android Studio](http://developer.android.com/sdk/index.html) версии 1.0 или более поздней.
22 | * [Java Development Kit (JDK) 7](http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html).
23 | * Учетная запись Office 365. Вы можете [подписаться на план Office 365 для разработчиков](https://aka.ms/devprogramsignup), включающий ресурсы, которые необходимы для создания приложений Office 365.
24 |
25 | > Примечание. Если у вас уже есть подписка, при выборе приведенной выше ссылки откроется страница с сообщением *К сожалению, вы не можете добавить это к своей учетной записи*. В этом случае используйте учетную запись, сопоставленную с текущей подпиской на Office 365.
26 | * Клиент Microsoft Azure для регистрации приложения. В Azure Active Directory доступны службы идентификации, которые приложения используют для проверки подлинности и авторизации. Здесь можно получить пробную подписку: [Microsoft Azure](https://account.windowsazure.com/SignUp).
27 |
28 | > Внимание! Убедитесь, что ваша подписка на Azure привязана к клиенту Office 365. Для этого просмотрите запись в блоге команды Active Directory, посвященную [созданию нескольких каталогов Microsoft Azure AD и управлению ими](http://blogs.technet.com/b/ad/archive/2013/11/08/creating-and-managing-multiple-windows-azure-active-directories.aspx). Инструкции приведены в разделе о **добавлении нового каталога**. Дополнительные сведения см. в статье [Как настроить среду разработки для Office 365](https://msdn.microsoft.com/office/office365/howto/setup-development-environment#bk_CreateAzureSubscription) и, в частности, в разделе **Связывание Azure AD и учетной записи Office 365 для создания приложений и управления ими**.
29 |
30 | * Универсальный код ресурса (URI) для перенаправления и идентификатор клиента, указанные при регистрации приложения в Azure. Этому примеру приложения необходимо предоставить разрешение **Отправка почты от имени пользователя** для **Microsoft Graph**. [Добавьте в Azure основное клиентское приложение](https://msdn.microsoft.com/office/office365/HowTo/add-common-consent-manually#bk_RegisterNativeApp) и [предоставьте ему необходимые разрешения](https://github.com/OfficeDev/O365-Android-Microsoft-Graph-Connect/wiki/Grant-permissions-to-the-Connect-application-in-Azure).
31 |
32 | ## Открытие примера с помощью Android Studio
33 |
34 | 1. Установите [Android Studio](http://developer.android.com/sdk/index.html) и добавьте пакеты SDK для Android в соответствии с [инструкциями](http://developer.android.com/sdk/installing/adding-packages.html) на сайте developer.android.com.
35 | 2. Скачайте или клонируйте этот пример.
36 | 3. Запустите Android Studio.
37 | 1. Закройте все открытые проекты, а затем выберите команду **Open an existing Android Studio project** (Открыть существующий проект Android Studio).
38 | 2. Перейдите в локальный репозиторий и выберите проект O365-Android-Microsoft-Graph-Connect. Нажмите кнопку **OK** (ОК).
39 |
40 | > Примечание. В Android Studio может появиться диалоговое окно с запросом на использование программы-оболочки Gradle. Нажмите кнопку **OK** (ОК).
41 | >
42 | > **Frameworks detected****Репозиторий поддержки Android**
43 | 4. Откройте файл Constants.java.
44 | 1. Найдите константу CLIENT_ID и присвойте ей строковое значение, которое равно идентификатору клиента, зарегистрированному в Azure Active Directory.
45 | 2. Найдите константу REDIRECT_URI и присвойте ей строковое значение, которое равно универсальному коду ресурса (URI) для перенаправления, зарегистрированному в Azure Active Directory.  для перенаправления в файле Constants")
46 |
47 | > Примечание. Если у вас нет значений CLIENT_ID и REDIRECT_URI, [добавьте основное клиентское приложение в Azure](https://msdn.microsoft.com/ru-ru/library/azure/dn132599.aspx#BKMK_Adding) и запишите CLIENT_ID и REDIRECT_URI.
48 |
49 | После сборки приложения Connect его можно запустить в эмуляторе или на устройстве. Выберите устройство с API уровня 15 или более высокого в диалоговом окне **Choose device** (Выбор устройства).
50 |
51 | Дополнительные сведения о примере приложения см. в статье [Вызов Microsoft Graph в приложении для Android](https://graph.microsoft.io/ru-ru/docs/platform/android).
52 |
53 | ## Вопросы и комментарии
54 |
55 | Мы будем рады получить от вас отзывы о проекте приложения Android, подключающегося к Office 365. Отправляйте нам свои вопросы и предложения в раздел этого репозитория, посвященный [проблемам](https://github.com/OfficeDev/O365-Android-Microsoft-Graph-Connect/issues).
56 |
57 | Общие вопросы о разработке решений для Office 365 следует публиковать на сайте [Stack Overflow](http://stackoverflow.com/questions/tagged/Office365+API). Обязательно помечайте свои вопросы и комментарии тегами [Office365] и [API].
58 |
59 | ## Дальнейшие действия
60 |
61 | В этом примере показаны только основные компоненты, необходимые приложениям для работы с Office 365. Интерфейсы API Office 365 значительно расширяют возможности ваших приложений. Например, пользователи могут управлять расписанием своего рабочего дня с помощью календаря, находить во всех файлах из OneDrive только нужные сведения, а также искать необходимых пользователей в своих списках контактов. Дополнительные данные см. в статье [Начальный проект API Office 365 для Android](https://github.com/officedev/O365-Android-Start/). Она поможет вам развить свои идеи.
62 |
63 | ## Дополнительные ресурсы
64 |
65 | * [Общие сведения о платформе API Office 365](https://msdn.microsoft.com/office/office365/howto/platform-development-overview)
66 | * [Начало работы с API Office 365](http://dev.office.com/getting-started/office365apis)
67 | * [Общие сведения о Microsoft Graph для Office 365](http://graph.microsoft.io)
68 | * [Пакет SDK Office 365 для Android](https://github.com/OfficeDev/Office-365-SDK-for-Android)
69 | * [Начальные проекты и примеры кода касательно API Office 365](https://msdn.microsoft.com/office/office365/howto/starter-projects-and-code-samples)
70 | * [Фрагменты кода из Microsoft Graph для доступа к Office 365 в Android](https://github.com/OfficeDev/O365-Android-Microsoft-Graph-Snippets)
71 | * [Начальный проект API Office 365 для Android](https://github.com/OfficeDev/O365-Android-Start)
72 | * [Пример профиля Office 365 для Android](https://github.com/OfficeDev/O365-Android-Profile)
73 |
74 |
75 | ## Авторские права
76 | (c) Корпорация Майкрософт (Microsoft Corporation), 2015. Все права защищены.
77 |
--------------------------------------------------------------------------------
/README-Localized/README-zh-cn.md:
--------------------------------------------------------------------------------
1 | # 使用 Microsoft Graph 的适于 Android 的 Office 365 Connect 示例
2 |
3 | 
4 |
5 | [ ](https://www.youtube.com/watch?v=3IQIDFrqhY4 "单击查看活动示例")
6 |
7 | 连接到 Office 365 是每个 Android 应用开始使用 Office 365 服务和数据必须采取的第一步。该示例演示如何通过 Microsoft Graph(旧称 Office 365 统一 API)连接并调用一个 API。
8 | > 注意: 尝试 [Office 365 API 入门](http://dev.office.com/getting-started/office365apis?platform=option-android#setup)页面,其简化了注册,使您可以更快地运行该示例。
9 |
10 | ## 设备要求
11 |
12 | 要运行该 Connect 示例,您的设备需要满足以下要求:
13 |
14 | * 800 x 480 或更大的屏幕尺寸。
15 | * Android API 级别为 15 级或更高。
16 |
17 | ## 先决条件
18 |
19 | 要使用适于 Android 的 Office 365 Connect 示例,您需要以下软件:
20 |
21 | * [Android Studio](http://developer.android.com/sdk/index.html) 1.0 或更高版本。
22 | * [Java Development Kit (JDK) 7](http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html)。
23 | * Office 365 帐户。您可以注册 [Office 365 开发人员订阅](https://aka.ms/devprogramsignup),其中包含您开始构建 Office 365 应用所需的资源。
24 |
25 | > 注意: 如果您已经订阅,之前的链接会将您转至包含以下信息的页面:*抱歉,您无法将其添加到当前帐户*。在这种情况下,请使用当前 Office 365 订阅中的帐户。
26 | * 用于注册您的应用程序的 Microsoft Azure 租户。Azure Active Directory 为应用程序提供了用于进行身份验证和授权的标识服务。您还可在此处获得试用订阅: [Microsoft Azure](https://account.windowsazure.com/SignUp)。
27 |
28 | > 重要说明: 您还需要确保您的 Azure 订阅已绑定到 Office 365 租户。要执行这一操作,请参阅 Active Directory 团队的博客文章:[创建和管理多个 Microsoft Azure Active Directory](http://blogs.technet.com/b/ad/archive/2013/11/08/creating-and-managing-multiple-windows-azure-active-directories.aspx)。**添加新目录**一节将介绍如何执行此操作。您还可以参阅[设置 Office 365 开发环境](https://msdn.microsoft.com/office/office365/howto/setup-development-environment#bk_CreateAzureSubscription)和**关联您的 Office 365 帐户和 Azure AD 以创建并管理应用**一节获取详细信息。
29 |
30 | * 在 Azure 中注册的应用程序的客户端 id 和重定向 uri 值。必须向该示例应用程序授予**以用户身份发送邮件**权限以使用 **Microsoft Graph**。[在 Azure 中添加本机客户端应用程序](https://msdn.microsoft.com/office/office365/HowTo/add-common-consent-manually#bk_RegisterNativeApp)并向其[授予适当的权限](https://github.com/OfficeDev/O365-Android-Microsoft-Graph-Connect/wiki/Grant-permissions-to-the-Connect-application-in-Azure)。
31 |
32 | ## 打开使用 Android Studio 的示例
33 |
34 | 1. 安装 [Android Studio](http://developer.android.com/sdk/index.html) 并根据 developer.android.com 上的[说明](http://developer.android.com/sdk/installing/adding-packages.html)添加 Android SDK 程序包。
35 | 2. 下载或克隆该示例。
36 | 3. 启动 Android Studio。
37 | 1. 关闭可能打开的任何项目,然后选择**打开一个现有的 Android Studio 项目**。
38 | 2. 浏览您的本地存储库,然后选择 O365-Android-Microsoft-Graph-Connect 项目。单击**确定**。
39 |
40 | > 注意: Android Studio 可能会显示一个对话框,询问您是否要使用 Gradle 包装器。单击**确定**。
41 | >
42 | > **检测到的框架****Android 支持存储库**
43 | 4. 打开 Constants.java 文件。
44 | 1. 查找 CLIENT_ID 常数并将其字符串值设置为与您在 Azure Active Directory 中注册的客户端 id 相等。
45 | 2. 查找 REDIRECT_URI 常数并将其字符串值设置为与您在 Azure Active Directory 中注册的重定向 URI 相等。
46 |
47 | > 注意: 如果您没有 CLIENT_ID 和 REDIRECT_URI 值,请[在 Azure 中添加本机客户端应用程序](https://msdn.microsoft.com/zh-cn/library/azure/dn132599.aspx#BKMK_Adding)并记录 CLIENT_ID 和 REDIRECT_URI。
48 |
49 | 建立 Connect 示例后,您可以在仿真器或设备中运行。在**选择设备**对话中选择配备了 15 级或更高级别的设备。
50 |
51 | 要了解有关该示例的详细信息,请参阅[在 Android 应用中调用 Microsoft Graph](https://graph.microsoft.io/zh-cn/docs/platform/android)。
52 |
53 | ## 问题和意见
54 |
55 | 我们乐意倾听您有关 Office 365 Android Connect 项目的反馈。您可以在该存储库中的[问题](https://github.com/OfficeDev/O365-Android-Microsoft-Graph-Connect/issues)部分将问题和建议发送给我们。
56 |
57 | 与 Office 365 开发相关的问题一般应发布在[堆栈溢出](http://stackoverflow.com/questions/tagged/Office365+API)中。确保您的问题或意见使用了 [Office365] 和 [API] 标记。
58 |
59 | ## 后续步骤
60 |
61 | 该示例只显示您的应用需要使用 Office 365 的必要程序。应用可以使用 Office 365 API 进行的工作非常之多,例如,帮助用户使用日历管理工作日,在存储于 OneDrive 中的所有文件中查找用户需要的信息,或在他们的联系人列表中找出他们需要的人员。我们在 [适于 Android 的 Office 365 API 初学者项目](https://github.com/officedev/O365-Android-Start/)中与您共享了更多内容。我们认为这有助于激起您的创意。
62 |
63 | ## 其他资源
64 |
65 | * [Office 365 API 平台概述](https://msdn.microsoft.com/office/office365/howto/platform-development-overview)
66 | * [Office 365 API 入门](http://dev.office.com/getting-started/office365apis)
67 | * [Office 365 Microsoft Graph 概述](http://graph.microsoft.io)
68 | * [适于 Android 的 Office 365 SDK](https://github.com/OfficeDev/Office-365-SDK-for-Android)
69 | * [Office 365 API 初学者项目和代码示例](https://msdn.microsoft.com/office/office365/howto/starter-projects-and-code-samples)
70 | * [Office 365 Android Microsoft Graph 片段](https://github.com/OfficeDev/O365-Android-Microsoft-Graph-Snippets)
71 | * [Android Office 365 API 初学者项目](https://github.com/OfficeDev/O365-Android-Start)
72 | * [Android Office 365 Profile 示例](https://github.com/OfficeDev/O365-Android-Profile)
73 |
74 |
75 | ## 版权所有
76 | 版权所有 (c) 2015 Microsoft。保留所有权利。
77 |
--------------------------------------------------------------------------------
/README-Localized/README-zh-tw.md:
--------------------------------------------------------------------------------
1 | # 使用 Microsoft Graph 的 Office 365 Connect 範例 (適用於 Android)
2 |
3 | 
4 |
5 | [ ](https://www.youtube.com/watch?v=3IQIDFrqhY4 "按一下以查看執行中的範例")
6 |
7 | 連接到 Office 365 是每個 Android 應用程式要開始使用 Office 365 服務和資料時必須採取的第一個步驟。此範例示範如何透過 Microsoft Graph (之前稱為 Office 365 統一 API) 連接而後呼叫一個 API。
8 | > 注意事項: 嘗試可簡化註冊的 [Office 365 API 入門](http://dev.office.com/getting-started/office365apis?platform=option-android#setup)頁面,以便您更快速地執行這個範例。
9 |
10 | ## 裝置需求
11 |
12 | 若要執行 Connect 範例,您的裝置必須符合下列需求:
13 |
14 | * 800 x 480 或更大的螢幕大小。
15 | * Android API 層級 15 或更高層級。
16 |
17 | ## 必要條件
18 |
19 | 若要使用 Android 適用的 Office 365 Connect 範例,您需要下列各項:
20 |
21 | * [Android Studio](http://developer.android.com/sdk/index.html) 1.0 版或更新版本。
22 | * [JAVA 開發套件 (JDK) 7](http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html)。
23 | * Office 365 帳戶。您可以註冊 [Office 365 開發人員訂用帳戶](https://aka.ms/devprogramsignup),其中包含開始建置 Office 365 應用程式所需的資源。
24 |
25 | > 注意事項: 如果您已有訂用帳戶,則先前的連結會讓您連到顯示「抱歉,您無法將之新增到您目前的帳戶」訊息的頁面。在此情況下,請使用您目前的 Office 365 訂用帳戶所提供的帳戶。
26 | * 用來註冊您的應用程式的 Microsoft Azure 租用戶。Azure Active Directory 會提供識別服務,以便應用程式用於驗證和授權。在這裡可以取得試用版的訂用帳戶: [Microsoft Azure](https://account.windowsazure.com/SignUp)。
27 |
28 | > 重要事項: 您還需要確定您的 Azure 訂用帳戶已繫結至您的 Office 365 租用戶。若要執行這項操作,請參閱 Active Directory 小組的部落格文章:[建立和管理多個 Windows Azure Active Directory](http://blogs.technet.com/b/ad/archive/2013/11/08/creating-and-managing-multiple-windows-azure-active-directories.aspx)。**新增目錄**一節將說明如何執行這項操作。如需詳細資訊,也可以參閱[設定 Office 365 開發環境](https://msdn.microsoft.com/office/office365/howto/setup-development-environment#bk_CreateAzureSubscription)和**建立 Office 365 帳戶與 Azure AD 的關聯以便建立和管理應用程式**一節。
29 |
30 | * 在 Azure 中註冊之應用程式的用戶端識別碼和重新導向 URI 值。此範例應用程式必須取得 **Microsoft Graph** 的 [以使用者身分傳送郵件] 權限。[在 Azure 中新增 Web 應用程式](https://msdn.microsoft.com/office/office365/HowTo/add-common-consent-manually#bk_RegisterNativeApp)和[授與適當的權限](https://github.com/OfficeDev/O365-Android-Microsoft-Graph-Connect/wiki/Grant-permissions-to-the-Connect-application-in-Azure)給它。
31 |
32 | ## 使用 Android Studio 開啟範例
33 |
34 | 1. 根據 developer.android.com 上的[指示](http://developer.android.com/sdk/installing/adding-packages.html),安裝 [Android Studio](http://developer.android.com/sdk/index.html) 及新增 Android SDK 套件。
35 | 2. 下載或複製這個範例。
36 | 3. 啟動 Android Studio。
37 | 1. 關閉您可能已開啟的任何專案,然後選擇 [開啟現有的 Android Studio 專案]。
38 | 2. 瀏覽至您的本機儲存機制,然後選擇 O365-Android-Microsoft-Graph-Connect 專案。按一下 [確定]。
39 |
40 | > 注意事項: Android Studio 可能會顯示一個對話方塊,詢問您是否要使用 Gradle 包裝函式。按一下 [確定]。
41 | >
42 | > **偵測到的架構****Android Support Repository**
43 | 4. 開啟 Constants.java 檔案。
44 | 1. 尋找 CLIENT_ID 常數並將其字串值設定為等於您在 Azure Active Directory 中註冊的用戶端識別碼。
45 | 2. 尋找 REDIRECT_URI 常數並將其字串值設定為等於您在 Azure Active Directory 中註冊的重新導向 URI。
46 | 
47 |
48 | > 注意事項: 如果您沒有 CLIENT_ID 和 REDIRECT_URI 值,請[在 Azure 中新增原生用戶端應用程式](https://msdn.microsoft.com/zh-tw/library/azure/dn132599.aspx#BKMK_Adding)並記下 CLIENT_ID 和 REDIRECT_URI。
49 |
50 | 一旦建置 Connect 範例,您可以在模擬器或裝置上執行它。從 [選擇裝置] 對話方塊挑選使用 API 層級 15 或更高層級的裝置。
51 |
52 | 若要深入了解此範例,請參閱[在 Android 應用程式中呼叫 Microsoft Graph](https://graph.microsoft.io/zh-tw/docs/platform/android)。
53 |
54 | ## 問題與意見
55 |
56 | 我們很樂於收到您對於 Office 365 Android Connect 專案的意見反應。您可以在此儲存機制的[問題](https://github.com/OfficeDev/O365-Android-Microsoft-Graph-Connect/issues)區段中,將您的問題及建議傳送給我們。
57 |
58 | 請在 [Stack Overflow](http://stackoverflow.com/questions/tagged/Office365+API) 提出有關 Office 365 開發的一般問題。務必以 [Office365] 和 [API] 標記您的問題或意見。
59 |
60 | ## 後續步驟
61 |
62 | 這個範例只會顯示您的應用程式要使用 Office 365 所需的基本資訊。您的應用程式可以使用 Office 365 API 做很多事,像是利用行事曆幫助您的使用者管理其工作天、在他們儲存於 OneDrive 的所有檔案中只尋找他們所需的資訊,或從他們的連絡人清單中找到她們真正需要的人。我們在[適用於 Android 的 Office 365 API 入門專案](https://github.com/officedev/O365-Android-Start/)中有更多資訊與您分享。我們認為這有助於激發您的想法。
63 |
64 | ## 其他資源
65 |
66 | * [Office 365 API 平台概觀](https://msdn.microsoft.com/office/office365/howto/platform-development-overview)
67 | * [Office 365 API 入門](http://dev.office.com/getting-started/office365apis)
68 | * [Office 365 Microsoft Graph 概觀](http://graph.microsoft.io)
69 | * [Office 365 SDK for Android](https://github.com/OfficeDev/Office-365-SDK-for-Android)
70 | * [Office 365 API 入門專案和程式碼範例](https://msdn.microsoft.com/office/office365/howto/starter-projects-and-code-samples)
71 | * [Office 365 Android Microsoft Graph 程式碼片段](https://github.com/OfficeDev/O365-Android-Microsoft-Graph-Snippets)
72 | * [適用於 Android 的 Office 365 API 入門專案](https://github.com/OfficeDev/O365-Android-Start)
73 | * [適用於 Android 的 Office 365 Profile 範例](https://github.com/OfficeDev/O365-Android-Profile)
74 |
75 |
76 | ## 著作權
77 | Copyright (c) 2015 Microsoft.著作權所有,並保留一切權利。
78 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Connect Sample for Android Using the Microsoft Graph REST endpoin
2 |
3 | >**Note:** We've updated this sample to use the [recommended auth library](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-libraries#compatible-client-libraries) for Android apps.
4 |
5 |
6 | > **Building apps for enterprise customers?** Your app may not work if your enterprise customer turns on enterprise mobility security features like conditional device access. In this case, you may not know and your customers may experience errors.
7 |
8 | > To support **all enterprise customers** across **all enterprise scenarios**, you must use the Azure AD endpoint and manage your apps using the [Azure Management Portal](https://aka.ms/aadapplist). For more information, see [Deciding between the Azure AD and Azure AD v2.0 endpoints](https://graph.microsoft.io/docs/authorization/auth_overview#deciding-between-azure-ad-and-the-v2-authentication-endpoint).
9 |
10 | [](https://www.youtube.com/watch?v=3IQIDFrqhY4 "Click to see the sample in action")
11 |
12 | Connecting to Microsoft Graph is the first step every Android app must take to start working with Office 365 services and data. This sample shows how to connect and then call one API through the Microsoft Graph REST endpoint.
13 |
14 | ## Device requirements
15 |
16 | To run the Connect sample, your device needs to meet the following requirements:
17 |
18 | * A screen size of 800 x 480 or larger.
19 | * Android API level 16 or higher.
20 |
21 | ## Prerequisites
22 |
23 | To use the Connect sample for Android, you need the following:
24 |
25 | * [Android Studio](http://developer.android.com/sdk/index.html) version 2.0 or later.
26 | * [Java Development Kit (JDK) 7](http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html).
27 |
28 |
29 | ## Register and configure the app
30 |
31 | 1. Sign into the [App Registration Portal](https://apps.dev.microsoft.com/) using either your personal or work or school account.
32 | 2. Select **Add an app**.
33 | 3. Enter a name for the app, and select **Create application**.
34 |
35 | The registration page displays, listing the properties of your app.
36 |
37 | 4. Under **Platforms**, select **Add platform**.
38 | 5. Select **Mobile application**.
39 | 6. Copy the **Application Id**, you'll need it in the next section.
40 | 7. Click **Save**.
41 |
42 | ## Open the sample using Android Studio
43 |
44 | 1. Install [Android Studio](http://developer.android.com/sdk/index.html) and add the Android SDK packages according to the [instructions](http://developer.android.com/sdk/installing/adding-packages.html) on developer.android.com.
45 | 2. Download or clone this sample.
46 | 3. Start Android Studio.
47 | 1. Close any projects that you might have open, and then choose **Open an existing Android Studio project**.
48 | 2. Browse to your local repository and choose the Android-Connect project. Click **OK**.
49 |
50 | > Note: Android Studio shows a **Frameworks detected** notification if you don't have the **Android Support Repository** installed. Open the SDK manager and add the Android Support Repository to avoid the Frameworks detected notification.
51 |
52 | 4. Open the Constants.java file.
53 | * Replace *ENTER_YOUR_CLIENT_ID* with the application id from the previous section.
54 |
55 | Once you've built the Connect sample, you can run it on an emulator or device. Pick a device with API level 16 or higher from the **Choose device** dialog.
56 |
57 | To learn more about the sample, see [Call Microsoft Graph in an Android app](https://graph.microsoft.io/en-us/docs/platform/android).
58 |
59 |
60 | ## Contributing ##
61 |
62 | If you'd like to contribute to this sample, see [CONTRIBUTING.MD](/CONTRIBUTING.md).
63 |
64 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
65 |
66 | ## Questions and comments
67 |
68 | We'd love to get your feedback about the Connect sample. You can send your questions and suggestions to us in the [Issues](issues) section of this repository.
69 |
70 | Questions about Microsoft Graph development in general should be posted to [Stack Overflow](http://stackoverflow.com/questions/tagged/MicrosoftGraph+API). Make sure that your questions or comments are tagged with [MicrosoftGraph] and [API].
71 |
72 | ## Next steps
73 |
74 | This sample just shows the essentials that your apps need to work with Microsoft Graph. There is so much more that your apps can do using the Office 365 APIs, like helping your users to manage their work day with calendar, find just the information they need in all the files they store in OneDrive, or find the exact person they need from their list of contacts. We have more to share with you in the [Snippets sample for Android](../../../android-java-snippets-rest-sample).
75 |
76 | ## Additional resources
77 |
78 | * [Get started with Office 365 APIs powered by Microsoft Graph](http://dev.office.com/getting-started/office365apis)
79 | * [Microsoft Graph overview](http://graph.microsoft.io)
80 | * [Microsoft Graph Explorer](https://developer.microsoft.com/en-us/graph/graph-explorer)
81 | * [Snippets sample for Android](../../../android-java-snippets-rest-sample)
82 | * [Add sign-in to an Android app using a third-party library with Graph API using the v2.0 endpoint](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-devquickstarts-android)
83 |
84 | ## Copyright
85 | Copyright (c) 2016 Microsoft. All rights reserved.
86 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion "23.0.2"
6 |
7 | defaultConfig {
8 | applicationId "com.microsoft.office365.connect"
9 | minSdkVersion 15
10 | targetSdkVersion 23
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFile 'proguard-rules.pro'
18 | }
19 | }
20 | lintOptions {
21 | disable 'InvalidPackage'
22 | }
23 | }
24 |
25 | dependencies {
26 | compile fileTree(dir: 'libs', include: ['*.jar'])
27 | compile 'com.android.support:appcompat-v7:23.3.0'
28 |
29 | // OIDCAndroidLib
30 | compile project(':oidclib')
31 |
32 | // Retrofit + custom HTTP
33 | compile 'com.squareup.okhttp3:okhttp:3.3.1'
34 | compile 'com.squareup.okhttp3:logging-interceptor:3.3.1'
35 | compile 'com.squareup.retrofit2:retrofit:2.1.0'
36 | compile 'com.squareup.retrofit2:converter-gson:2.1.0'
37 |
38 | // Test
39 | testCompile 'junit:junit:4.12'
40 | }
41 |
--------------------------------------------------------------------------------
/app/dailyBuild.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion "23.0.3"
6 |
7 | defaultConfig {
8 | applicationId "com.microsoft.office365.connect"
9 | minSdkVersion 15
10 | targetSdkVersion 23
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFile 'proguard-rules.pro'
18 | }
19 | }
20 | lintOptions {
21 | disable 'InvalidPackage'
22 | }
23 | }
24 |
25 | dependencies {
26 | compile fileTree(dir: 'libs', include: ['*.jar'])
27 | compile 'com.android.support:appcompat-v7:+'
28 |
29 | // OIDCAndroidLib
30 | compile project(':oidclib')
31 |
32 | // Retrofit + custom HTTP
33 | compile 'com.squareup.okhttp3:okhttp:+'
34 | compile 'com.squareup.okhttp3:logging-interceptor:+'
35 | compile 'com.squareup.retrofit2:retrofit:+'
36 | compile 'com.squareup.retrofit2:converter-gson:+'
37 |
38 | // Test
39 | testCompile 'junit:junit:+'
40 | }
41 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in C:\Program Files (x86)\Android\android-sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
18 |
22 |
23 |
24 |
25 |
26 |
27 |
32 |
35 |
36 |
37 |
40 |
41 |
42 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
86 |
--------------------------------------------------------------------------------
/app/src/main/java/com/microsoft/office365/connectmicrosoftgraph/AuthenticationCallback.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
3 | * See LICENSE in the project root for license information.
4 | */
5 | package com.microsoft.office365.connectmicrosoftgraph;
6 |
7 | interface AuthenticationCallback {
8 | void onSuccess(T data);
9 | void onError(Exception e);
10 | }
11 |
--------------------------------------------------------------------------------
/app/src/main/java/com/microsoft/office365/connectmicrosoftgraph/AuthenticationManager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
3 | * See LICENSE in the project root for license information.
4 | */
5 | package com.microsoft.office365.connectmicrosoftgraph;
6 |
7 | import android.accounts.Account;
8 | import android.accounts.AccountManagerCallback;
9 | import android.accounts.AccountManagerFuture;
10 | import android.accounts.AuthenticatorException;
11 | import android.accounts.OperationCanceledException;
12 | import android.app.Activity;
13 | import android.content.Context;
14 | import android.content.SharedPreferences;
15 | import android.os.Bundle;
16 |
17 | import com.lnikkila.oidc.OIDCAccountManager;
18 | import com.lnikkila.oidc.OIDCRequestManager;
19 | import com.lnikkila.oidc.security.UserNotAuthenticatedWrapperException;
20 |
21 | import java.io.IOException;
22 |
23 | /**
24 | * Handles setup of ADAL Dependency Resolver for use in API clients.
25 | */
26 |
27 | public class AuthenticationManager {
28 |
29 | private static final String TAG = "AuthenticationManager";
30 | private static AuthenticationManager INSTANCE;
31 |
32 | private OIDCAccountManager mOIDCAccountManager;
33 |
34 | private AuthenticationManager() {
35 | }
36 |
37 | public static synchronized AuthenticationManager getInstance(Context context) {
38 | if (INSTANCE == null) {
39 | INSTANCE = new AuthenticationManager();
40 | INSTANCE.mOIDCAccountManager = new OIDCAccountManager(context);
41 | SharedPreferences sharedPreferences = context.getSharedPreferences("oidc_clientconf", Context.MODE_PRIVATE);
42 | SharedPreferences.Editor editor = sharedPreferences.edit();
43 | editor.putBoolean("oidc_loadfromprefs", true);
44 |
45 | //Was false. When false, exception is thrown in OIDCRequestManager, line 378. id is null
46 | editor.putBoolean("oidc_oauth2only", false);
47 | editor.putString("oidc_clientId", Constants.CLIENT_ID);
48 | editor.putString("oidc_redirectUrl", Constants.REDIRECT_URI);
49 | editor.putString("oidc_scopes", Constants.SCOPES);
50 | editor.putString("oidc_flowType", OIDCRequestManager.Flows.Code.name());
51 |
52 | editor.apply();
53 | }
54 | return INSTANCE;
55 | }
56 |
57 | public static synchronized void resetInstance() {
58 | INSTANCE = null;
59 | }
60 |
61 | /**
62 | * Returns the access token obtained in authentication
63 | *
64 | * @return mAccessToken
65 | */
66 | public String getAccessToken() throws AuthenticatorException, IOException, OperationCanceledException, UserNotAuthenticatedWrapperException {
67 | return mOIDCAccountManager.getAccessToken(mOIDCAccountManager.getAccounts()[0], null);
68 | }
69 |
70 | /**
71 | *
72 | * @param authenticationCallback The callback to notify when the processing is finished.
73 | */
74 | public void connect(Activity activity, final AuthenticationCallback authenticationCallback) {
75 | switch (mOIDCAccountManager.getAccounts().length) {
76 | // No account has been created, let's create one now
77 | case 0:
78 | mOIDCAccountManager.createAccount(activity, new AccountManagerCallback() {
79 | @Override
80 | public void run(AccountManagerFuture futureManager) {
81 | // Unless the account creation was cancelled, try logging in again
82 | // after the account has been created.
83 | if (!futureManager.isCancelled()) {
84 | new Thread(new Runnable() {
85 | @Override
86 | public void run() {
87 | Account account = mOIDCAccountManager.getAccounts()[0];
88 | try {
89 | authenticationCallback.onSuccess(mOIDCAccountManager.getIdToken(account.name, null));
90 | } catch (AuthenticatorException | UserNotAuthenticatedWrapperException | OperationCanceledException | IOException e) {
91 | authenticationCallback.onError(e);
92 | }
93 | }
94 | }).start();
95 | } else {
96 | authenticationCallback.onError(new AuthenticatorException("Flow was canceled"));
97 | }
98 | }
99 | });
100 | break;
101 | case 1:
102 | // if we have an user endpoint we try to get userinfo with the receive token
103 | new Thread(new Runnable() {
104 | @Override
105 | public void run() {
106 | Account account = mOIDCAccountManager.getAccounts()[0];
107 | try {
108 | authenticationCallback.onSuccess(mOIDCAccountManager.getIdToken(account.name, null));
109 | } catch (AuthenticatorException | UserNotAuthenticatedWrapperException | OperationCanceledException | IOException e) {
110 | authenticationCallback.onError(e);
111 | }
112 | }
113 | }).start();
114 | break;
115 | }
116 | }
117 |
118 | /**
119 | * Disconnects the app from Office 365 by clearing the token cache, setting the client objects
120 | * to null, and removing the user id from shred preferences.
121 | */
122 | public void disconnect() {
123 | mOIDCAccountManager.removeAccount(mOIDCAccountManager.getAccounts()[0]);
124 | // Reset the AuthenticationManager object
125 | AuthenticationManager.resetInstance();
126 | }
127 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/microsoft/office365/connectmicrosoftgraph/ConnectActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
3 | * See LICENSE in the project root for license information.
4 | */
5 | package com.microsoft.office365.connectmicrosoftgraph;
6 |
7 | import android.content.Intent;
8 | import android.os.Bundle;
9 | import android.support.v7.app.AppCompatActivity;
10 | import android.util.Log;
11 | import android.view.View;
12 | import android.widget.Button;
13 | import android.widget.ProgressBar;
14 | import android.widget.TextView;
15 | import android.widget.Toast;
16 |
17 | import com.google.api.client.auth.openidconnect.IdToken;
18 | import com.google.api.client.json.gson.GsonFactory;
19 |
20 | import java.io.IOException;
21 | import java.net.URI;
22 | import java.util.UUID;
23 |
24 | /**
25 | * Starting Activity of the app. Handles the connection to Office 365.
26 | * When it first starts it only displays a button to Connect to Office 365.
27 | * If there are no cached tokens, the user is required to sign in to Office 365.
28 | * If there are cached tokens, the app tries to reuse them.
29 | * The activity redirects the user to the SendMailActivity upon successful connection.
30 | */
31 | public class ConnectActivity extends AppCompatActivity {
32 |
33 | private static final String TAG = "ConnectActivity";
34 |
35 | private Button mConnectButton;
36 | private TextView mTitleTextView;
37 | private TextView mDescriptionTextView;
38 | private ProgressBar mConnectProgressBar;
39 |
40 |
41 | @Override
42 | protected void onCreate(Bundle savedInstanceState) {
43 | super.onCreate(savedInstanceState);
44 | setContentView(R.layout.activity_connect);
45 |
46 | // set up our views
47 | mConnectButton = (Button) findViewById(R.id.connectButton);
48 | mConnectProgressBar = (ProgressBar) findViewById(R.id.connectProgressBar);
49 | mTitleTextView = (TextView) findViewById(R.id.titleTextView);
50 | mDescriptionTextView = (TextView) findViewById(R.id.descriptionTextView);
51 |
52 | // add click listener
53 | mConnectButton.setOnClickListener(new View.OnClickListener() {
54 | @Override
55 | public void onClick(View v) {
56 | showConnectingInProgressUI();
57 |
58 | //check that client id and redirect have been configured
59 | if (!hasAzureConfiguration()) {
60 | Toast.makeText(
61 | ConnectActivity.this,
62 | getString(R.string.warning_clientid_redirecturi_incorrect),
63 | Toast.LENGTH_LONG).show();
64 | resetUIForConnect();
65 | return;
66 | }
67 |
68 | connect();
69 | }
70 | });
71 | }
72 |
73 | private void connect() {
74 | // define the post-auth callback
75 | AuthenticationCallback callback =
76 | new AuthenticationCallback() {
77 |
78 | @Override
79 | public void onSuccess(String idToken) {
80 | String name = "";
81 | String preferredUsername = "";
82 | try {
83 | // get the user info from the id token
84 | IdToken claims = IdToken.parse(new GsonFactory(), idToken);
85 | name = claims.getPayload().get("name").toString();
86 | preferredUsername = claims.getPayload().get("preferred_username").toString();
87 | } catch (IOException ioe) {
88 | Log.e(TAG, ioe.getMessage());
89 | } catch (NullPointerException npe) {
90 | Log.e(TAG, npe.getMessage());
91 |
92 | }
93 |
94 | // Prepare the SendMailActivity intent
95 | Intent sendMailActivity =
96 | new Intent(ConnectActivity.this, SendMailActivity.class);
97 |
98 | // take the user's info along
99 | sendMailActivity.putExtra(SendMailActivity.ARG_GIVEN_NAME, name);
100 | sendMailActivity.putExtra(SendMailActivity.ARG_DISPLAY_ID, preferredUsername);
101 |
102 | // actually start the activity
103 | startActivity(sendMailActivity);
104 |
105 | resetUIForConnect();
106 | }
107 |
108 | @Override
109 | public void onError(Exception exc) {
110 | showConnectErrorUI();
111 | }
112 | };
113 |
114 | AuthenticationManager mgr = AuthenticationManager.getInstance(this);
115 | mgr.connect(this, callback);
116 | }
117 |
118 | private static boolean hasAzureConfiguration() {
119 | try {
120 | UUID.fromString(Constants.CLIENT_ID);
121 | URI.create(Constants.REDIRECT_URI);
122 | return true;
123 | } catch (IllegalArgumentException e) {
124 | return false;
125 | }
126 | }
127 |
128 | private void resetUIForConnect() {
129 | runOnUiThread(new Runnable() {
130 | @Override
131 | public void run() {
132 | mConnectButton.setVisibility(View.VISIBLE);
133 | mTitleTextView.setVisibility(View.GONE);
134 | mDescriptionTextView.setVisibility(View.GONE);
135 | mConnectProgressBar.setVisibility(View.GONE);
136 | }
137 | });
138 | }
139 |
140 | private void showConnectingInProgressUI() {
141 | mConnectButton.setVisibility(View.GONE);
142 | mTitleTextView.setVisibility(View.GONE);
143 | mDescriptionTextView.setVisibility(View.GONE);
144 | mConnectProgressBar.setVisibility(View.VISIBLE);
145 | }
146 |
147 | private void showConnectErrorUI() {
148 | mConnectButton.setVisibility(View.VISIBLE);
149 | mConnectProgressBar.setVisibility(View.GONE);
150 | mTitleTextView.setText(R.string.title_text_error);
151 | mTitleTextView.setVisibility(View.VISIBLE);
152 | mDescriptionTextView.setText(R.string.connect_text_error);
153 | mDescriptionTextView.setVisibility(View.VISIBLE);
154 | Toast.makeText(
155 | ConnectActivity.this,
156 | R.string.connect_toast_text_error,
157 | Toast.LENGTH_LONG).show();
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/app/src/main/java/com/microsoft/office365/connectmicrosoftgraph/Constants.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
3 | * See LICENSE in the project root for license information.
4 | */
5 | package com.microsoft.office365.connectmicrosoftgraph;
6 |
7 |
8 | /*
9 | These constant values configure the client app to use OAuth2 and open id connect
10 | to authenticate with Azure and authorize the app to access the specified scopes.
11 | Read more about scopes: https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-scopes
12 | */
13 | interface Constants {
14 | String AUTHORITY_URL = "https://login.microsoftonline.com/common";
15 | // Update these two constants with the values for your application:
16 | String CLIENT_ID = "ENTER_YOUR_CLIENT_ID";
17 | String REDIRECT_URI = "https://login.microsoftonline.com/common/oauth2/nativeclient";
18 | String MICROSOFT_GRAPH_API_ENDPOINT_RESOURCE_ID = "https://graph.microsoft.com/";
19 | String SCOPES = "openid profile User.Read Mail.Send offline_access";
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/app/src/main/java/com/microsoft/office365/connectmicrosoftgraph/MSGraphAPIController.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
3 | * See LICENSE in the project root for license information.
4 | */
5 | package com.microsoft.office365.connectmicrosoftgraph;
6 |
7 | import android.content.Context;
8 |
9 | import com.microsoft.office365.connectmicrosoftgraph.vo.BodyVO;
10 | import com.microsoft.office365.connectmicrosoftgraph.vo.EmailAddressVO;
11 | import com.microsoft.office365.connectmicrosoftgraph.vo.MessageVO;
12 | import com.microsoft.office365.connectmicrosoftgraph.vo.MessageWrapper;
13 | import com.microsoft.office365.connectmicrosoftgraph.vo.ToRecipientsVO;
14 |
15 | import okhttp3.Interceptor;
16 | import retrofit2.Call;
17 |
18 |
19 | /**
20 | * Handles the creation of the message and contacting the
21 | * mail service to send the message. The app must have
22 | * connected to Office 365 and discovered the mail service
23 | * endpoints before using the createDraftMail method.
24 | */
25 | public class MSGraphAPIController {
26 |
27 | private MSGraphAPIService mMSGraphAPIService;
28 |
29 | public MSGraphAPIController(Context context) {
30 | mMSGraphAPIService = new RESTHelper()
31 | .getRetrofit(context)
32 | .create(MSGraphAPIService.class);
33 | }
34 |
35 | public MSGraphAPIController(Interceptor interceptor) {
36 | mMSGraphAPIService = new RESTHelper()
37 | .getRetrofit(interceptor)
38 | .create(MSGraphAPIService.class);
39 | }
40 |
41 | /**
42 | * Sends an email message using the Microsoft Graph API on Office 365. The mail is sent
43 | * from the address of the signed in user.
44 | *
45 | * @param emailAddress The recipient email address.
46 | * @param subject The subject to use in the mail message.
47 | * @param body The body of the message.
48 | */
49 | public Call sendMail(
50 | final String emailAddress,
51 | final String subject,
52 | final String body) {
53 | // create the email
54 | MessageWrapper msg = createMailPayload(subject, body, emailAddress);
55 |
56 | // send it using our service
57 | return mMSGraphAPIService.sendMail("application/json", msg);
58 | }
59 |
60 | private MessageWrapper createMailPayload(
61 | String subject,
62 | String body,
63 | String address) {
64 | EmailAddressVO emailAddressVO = new EmailAddressVO();
65 | emailAddressVO.mAddress = address;
66 |
67 | ToRecipientsVO toRecipientsVO = new ToRecipientsVO();
68 | toRecipientsVO.emailAddress = emailAddressVO;
69 |
70 | BodyVO bodyVO = new BodyVO();
71 | bodyVO.mContentType = "HTML";
72 | bodyVO.mContent = body;
73 |
74 | MessageVO sampleMsg = new MessageVO();
75 | sampleMsg.mSubject = subject;
76 | sampleMsg.mBody = bodyVO;
77 | sampleMsg.mToRecipients = new ToRecipientsVO[]{toRecipientsVO};
78 |
79 | return new MessageWrapper(sampleMsg);
80 | }
81 |
82 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/microsoft/office365/connectmicrosoftgraph/MSGraphAPIService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
3 | * See LICENSE in the project root for license information.
4 | */
5 | package com.microsoft.office365.connectmicrosoftgraph;
6 |
7 | import com.microsoft.office365.connectmicrosoftgraph.vo.MessageWrapper;
8 |
9 | import retrofit2.Call;
10 | import retrofit2.http.Body;
11 | import retrofit2.http.Header;
12 | import retrofit2.http.POST;
13 |
14 |
15 | public interface MSGraphAPIService {
16 | @POST("/v1.0/me/microsoft.graph.sendmail")
17 | Call sendMail(
18 | @Header("Content-type") String contentTypeHeader,
19 | @Body MessageWrapper mail);
20 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/microsoft/office365/connectmicrosoftgraph/RESTHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
3 | * See LICENSE in the project root for license information.
4 | */
5 | package com.microsoft.office365.connectmicrosoftgraph;
6 |
7 | import android.accounts.AuthenticatorException;
8 | import android.accounts.OperationCanceledException;
9 | import android.content.Context;
10 | import android.util.Log;
11 |
12 | import com.lnikkila.oidc.security.UserNotAuthenticatedWrapperException;
13 |
14 | import java.io.IOException;
15 |
16 | import okhttp3.Interceptor;
17 | import okhttp3.OkHttpClient;
18 | import okhttp3.Request;
19 | import okhttp3.Response;
20 | import okhttp3.logging.HttpLoggingInterceptor;
21 | import retrofit2.Retrofit;
22 | import retrofit2.converter.gson.GsonConverterFactory;
23 |
24 |
25 | public class RESTHelper {
26 | private static final String TAG = "RESTHelper";
27 |
28 | /**
29 | * Returns a retrofit rest adaptor class. The adaptor is created in calling code.
30 | *
31 | * @return A new RestAdapter instance.
32 | */
33 | public Retrofit getRetrofit(final Context context) {
34 | //This method catches outgoing REST calls and injects the Authorization and host headers before
35 | //sending to REST endpoint
36 | Interceptor interceptor = new Interceptor() {
37 | @Override
38 | public Response intercept(Chain chain) throws IOException {
39 | try {
40 | final String token = AuthenticationManager.getInstance(context).getAccessToken();
41 | Request request = chain.request();
42 | request = request.newBuilder()
43 | .addHeader("Authorization", "Bearer " + token)
44 | // This header has been added to identify this sample in the Microsoft Graph service.
45 | // If you're using this code for your project please remove the following line.
46 | .addHeader("SampleID", "android-java-connect-rest-sample")
47 | .build();
48 |
49 | Response response = chain.proceed(request);
50 | return response;
51 | } catch (AuthenticatorException | IOException | UserNotAuthenticatedWrapperException | OperationCanceledException e) {
52 | Log.e(TAG, e.getMessage());
53 | return null;
54 | }
55 | }
56 | };
57 |
58 | return getRetrofit(interceptor);
59 | }
60 |
61 | public Retrofit getRetrofit(Interceptor interceptor) {
62 | HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
63 | logging.setLevel(HttpLoggingInterceptor.Level.HEADERS);
64 |
65 | OkHttpClient client = new OkHttpClient.Builder()
66 | .addInterceptor(interceptor)
67 | .addInterceptor(logging)
68 | .build();
69 |
70 | //Sets required properties in rest adaptor class before it is created.
71 | return new Retrofit.Builder()
72 | .baseUrl(Constants.MICROSOFT_GRAPH_API_ENDPOINT_RESOURCE_ID)
73 | .client(client)
74 | .addConverterFactory(GsonConverterFactory.create())
75 | .build();
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/app/src/main/java/com/microsoft/office365/connectmicrosoftgraph/SendMailActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
3 | * See LICENSE in the project root for license information.
4 | */
5 | package com.microsoft.office365.connectmicrosoftgraph;
6 |
7 | import android.content.Intent;
8 | import android.os.Bundle;
9 | import android.support.v7.app.AppCompatActivity;
10 | import android.view.Menu;
11 | import android.view.MenuItem;
12 | import android.view.View;
13 | import android.widget.EditText;
14 | import android.widget.ImageButton;
15 | import android.widget.ProgressBar;
16 | import android.widget.TextView;
17 | import android.widget.Toast;
18 |
19 | import retrofit2.Call;
20 | import retrofit2.Callback;
21 | import retrofit2.Response;
22 |
23 | /**
24 | * This activity handles the send mail operation of the app.
25 | * The app must be connected to Office 365 before this activity can send an email.
26 | * It also uses the MSGraphAPIController to send the message.
27 | */
28 | public class SendMailActivity extends AppCompatActivity {
29 |
30 | // arguments for this activity
31 | public static final String ARG_GIVEN_NAME = "givenName";
32 | public static final String ARG_DISPLAY_ID = "displayableId";
33 |
34 | // views
35 | private EditText mEmailEditText;
36 | private ImageButton mSendMailButton;
37 | private ProgressBar mSendMailProgressBar;
38 | private String mGivenName;
39 | private TextView mConclusionTextView;
40 |
41 | @Override
42 | protected void onCreate(Bundle savedInstanceState) {
43 | super.onCreate(savedInstanceState);
44 | setContentView(R.layout.activity_send_mail);
45 |
46 | // find the views
47 | TextView mTitleTextView = (TextView) findViewById(R.id.titleTextView);
48 | mEmailEditText = (EditText) findViewById(R.id.emailEditText);
49 | mSendMailButton = (ImageButton) findViewById(R.id.sendMailButton);
50 | mSendMailProgressBar = (ProgressBar) findViewById(R.id.sendMailProgressBar);
51 | mConclusionTextView = (TextView) findViewById(R.id.conclusionTextView);
52 |
53 | // Extract the givenName and displayableId and use it in the UI.
54 | mGivenName = getIntent().getStringExtra(ARG_GIVEN_NAME);
55 | mTitleTextView.append(mGivenName + "!");
56 | mEmailEditText.setText(getIntent().getStringExtra(ARG_DISPLAY_ID));
57 | }
58 |
59 | /**
60 | * Handler for the onclick event of the send mail button. It uses the MSGraphAPIController to
61 | * send an email. When the call is completed, the call will return to either the success()
62 | * or failure() methods in this class which will then take the next steps on the UI.
63 | * This method sends the email using the address stored in the mEmailEditText view.
64 | * The subject and body of the message is stored in the strings.xml file.
65 | *
66 | * @param v The view.
67 | */
68 | public void onSendMailButtonClick(View v) {
69 | resetUIForSendMail();
70 |
71 | //Prepare body message and insert name of sender
72 | String body = getString(R.string.mail_body_text);
73 | body = body.replace("{0}", mGivenName);
74 |
75 | Call result = new MSGraphAPIController(this).sendMail(
76 | mEmailEditText.getText().toString(),
77 | getString(R.string.mail_subject_text),
78 | body);
79 |
80 | result.enqueue(new Callback() {
81 | @Override
82 | public void onResponse(Call call, Response response) {
83 | if(response.isSuccessful()) {
84 | showSendMailSuccessUI();
85 | } else {
86 | showSendMailErrorUI();
87 | }
88 | }
89 |
90 | @Override
91 | public void onFailure(Call call, Throwable t) {
92 | showSendMailErrorUI();
93 | }
94 | });
95 | }
96 |
97 | @Override
98 | public boolean onCreateOptionsMenu(Menu menu) {
99 | // Inflate the menu; this adds items to the action bar if it is present.
100 | getMenuInflater().inflate(R.menu.send_mail, menu);
101 | return true;
102 | }
103 |
104 | @Override
105 | public boolean onOptionsItemSelected(MenuItem item) {
106 | switch (item.getItemId()) {
107 | case R.id.disconnectMenuitem:
108 | AuthenticationManager.getInstance(this).disconnect();
109 | Intent connectIntent = new Intent(this, ConnectActivity.class);
110 | startActivity(connectIntent);
111 | finish();
112 | return true;
113 | default:
114 | return super.onOptionsItemSelected(item);
115 | }
116 | }
117 |
118 | private void resetUIForSendMail() {
119 | mSendMailButton.setVisibility(View.GONE);
120 | mConclusionTextView.setVisibility(View.GONE);
121 | mSendMailProgressBar.setVisibility(View.VISIBLE);
122 | }
123 |
124 | private void showSendMailSuccessUI() {
125 | mSendMailProgressBar.setVisibility(View.GONE);
126 | mSendMailButton.setVisibility(View.VISIBLE);
127 | mConclusionTextView.setText(R.string.conclusion_text);
128 | mConclusionTextView.setVisibility(View.VISIBLE);
129 | Toast.makeText(
130 | SendMailActivity.this,
131 | R.string.send_mail_toast_text,
132 | Toast.LENGTH_SHORT).show();
133 | }
134 |
135 | private void showSendMailErrorUI() {
136 | mSendMailProgressBar.setVisibility(View.GONE);
137 | mSendMailButton.setVisibility(View.VISIBLE);
138 | mConclusionTextView.setText(R.string.sendmail_text_error);
139 | mConclusionTextView.setVisibility(View.VISIBLE);
140 | Toast.makeText(
141 | SendMailActivity.this,
142 | R.string.send_mail_toast_text_error,
143 | Toast.LENGTH_LONG).show();
144 | }
145 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/microsoft/office365/connectmicrosoftgraph/vo/BodyVO.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
3 | * See LICENSE in the project root for license information.
4 | */
5 | package com.microsoft.office365.connectmicrosoftgraph.vo;
6 |
7 | import com.google.gson.annotations.SerializedName;
8 |
9 | public class BodyVO {
10 |
11 | @SerializedName("ContentType")
12 | public String mContentType;
13 |
14 | @SerializedName("Content")
15 | public String mContent;
16 |
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/microsoft/office365/connectmicrosoftgraph/vo/EmailAddressVO.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
3 | * See LICENSE in the project root for license information.
4 | */
5 | package com.microsoft.office365.connectmicrosoftgraph.vo;
6 |
7 | import com.google.gson.annotations.SerializedName;
8 |
9 | public class EmailAddressVO {
10 |
11 | @SerializedName("Address")
12 | public String mAddress;
13 |
14 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/microsoft/office365/connectmicrosoftgraph/vo/MessageVO.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
3 | * See LICENSE in the project root for license information.
4 | */
5 | package com.microsoft.office365.connectmicrosoftgraph.vo;
6 |
7 | import com.google.gson.annotations.SerializedName;
8 |
9 | /**
10 | * Mail Value Object for holding values in an email
11 | */
12 | public class MessageVO {
13 |
14 | @SerializedName("Subject")
15 | public String mSubject;
16 |
17 | @SerializedName("Body")
18 | public BodyVO mBody;
19 |
20 | @SerializedName("ToRecipients")
21 | public ToRecipientsVO[] mToRecipients;
22 |
23 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/microsoft/office365/connectmicrosoftgraph/vo/MessageWrapper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
3 | * See LICENSE in the project root for license information.
4 | */
5 | package com.microsoft.office365.connectmicrosoftgraph.vo;
6 |
7 | import com.google.gson.annotations.SerializedName;
8 |
9 | public class MessageWrapper {
10 |
11 | @SerializedName("Message")
12 | public MessageVO mMessage;
13 |
14 | public MessageWrapper(MessageVO msg) {
15 | mMessage = msg;
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/microsoft/office365/connectmicrosoftgraph/vo/ToRecipientsVO.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
3 | * See LICENSE in the project root for license information.
4 | */
5 | package com.microsoft.office365.connectmicrosoftgraph.vo;
6 |
7 | import com.google.gson.annotations.SerializedName;
8 |
9 | public class ToRecipientsVO {
10 |
11 | @SerializedName("EmailAddress")
12 | public EmailAddressVO emailAddress;
13 |
14 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoftgraph/android-java-connect-rest-sample/ba07bf5b7304c1e18eccdb5c008450605b696ac7/app/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/mail_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoftgraph/android-java-connect-rest-sample/ba07bf5b7304c1e18eccdb5c008450605b696ac7/app/src/main/res/drawable-mdpi/mail_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_connect.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
20 |
21 |
28 |
29 |
38 |
39 |
48 |
49 |
50 |
51 |
79 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_send_mail.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
22 |
23 |
32 |
33 |
41 |
42 |
51 |
52 |
59 |
60 |
69 |
70 |
71 |
72 |
100 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/send_mail.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 48dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/identifiers.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | com.microsoft.graph.connect.account
9 |
10 |
11 | Connect Sample Account
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Connect sample
6 | Connect to Office 365
7 | Disconnect
8 | Hi\u00A0
9 | \nYou\'re now connected to Office 365. Tap the mail icon below to send a message from your account using the Microsoft Graph API.\n
10 | \nCheck your inbox. You have a new message :)
11 |
12 |
13 | Connected to Office 365
14 | Found Office 365 mail service
15 | Mail sent
16 | Disconnected from Office 365
17 |
18 |
19 | Oops!
20 | \nSorry, can\'t connect to Office 365.\nHint: Check logcat for details.
21 | \nSorry, can\'t find the mail service.\nHint: Check logcat for details.
22 | \nSorry, can\'t send the email.\nHint: Check logcat for details.
23 |
24 |
25 | Error connecting to Office 365\nCheck logcat for details
26 | Error finding mail service\nCheck logcat for details
27 | Error sending email\nCheck logcat for details
28 | The client ID or redirect URI is not valid. Enter a valid client ID and redirect URI in the Constants.java file and run again
29 |
30 |
31 | Welcome to Microsoft Graph development on Android with the Connect sample
32 | <html><head>
33 | <meta http-equiv=\'Content-Type\' content=\'text/html; charset=us-ascii\'>
34 | <title></title>
35 | </head>
36 | <body style=\'font-family:calibri\'>
37 | <h2>Congratulations, {0}!</h2>
38 | <p>This is a message from the Microsoft Graph Connect sample. You are well on your way to incorporating Microsoft services in your apps.
39 | </p>
40 | <h3>What’s next?</h3>
41 | <ul>
42 | <li>Check out <a href=\'https://graph.microsoft.io\'>graph.microsoft.io</a> to start building Microsoft Graph apps today with all the latest tools, templates, and guidance to get started quickly.</li>
43 | <li>Use the <a href=\'https://graph.microsoft.io/graph-explorer\'>Graph Explorer</a> to start your testing.</li>
44 | <li>Browse other <a href=\'https://github.com/microsoftgraph\'>samples on GitHub</a> to see more of the APIs in action.</li>
45 | </ul>
46 | <h3>Give us feedback</h3>
47 | <ul>
48 | <li>If you have any trouble running this sample, please <a href=\'https://github.com/microsoftgraph/android-java-connect-rest-sample/issues\'>log an issue</a>.</li>
49 | <li>For general questions about the Microsoft Graph APIs, post to <a href=\'https://stackoverflow.com/questions/tagged/microsoftgraph?sort=newest\'>Stack Overflow</a>. Make sure that your questions or comments are tagged with [MicrosoftGraph].</li>
50 | </ul>
51 | <p>Thanks, and happy coding!<br>
52 | Your Microsoft Graph Development team </p>
53 | <div style=\'text-align:center; font-family:calibri\'>
54 | <table style=\'width:100%; font-family:calibri\'>
55 | <tbody>
56 | <tr>
57 | <td><a href=\'https://github.com/microsoftgraph/android-java-connect-rest-sample\'>See on GitHub</a>
58 | </td>
59 | <td><a href=\'https://officespdev.uservoice.com\'>Suggest on UserVoice</a>
60 | </td>
61 | <td><a href=\'https://twitter.com/intent/tweet?text=I%20just%20started%20developing%20apps%20for%20Android%20using%20the%20Microsoft%20Graph%20Connect%20sample&url=https://github.com/microsoftgraph/android-java-rest-connect-sample&hashtags=Android,MicrosoftGraph\'>Share on Twitter</a>
62 | </td>
63 | </tr>
64 | </tbody>
65 | </table>
66 | </div>
67 | </body>
68 | </html>
69 |
70 |
71 |
99 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/test/java/com/microsoft/office365/connectmicrosoftgraph/ConnectUnitTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
3 | * See LICENSE in the project root for license information.
4 | */
5 | package com.microsoft.office365.connectmicrosoftgraph;
6 |
7 | import com.google.gson.JsonObject;
8 | import com.google.gson.JsonParser;
9 |
10 | import org.json.JSONException;
11 | import org.junit.Assert;
12 | import org.junit.BeforeClass;
13 | import org.junit.Test;
14 |
15 | import java.io.BufferedReader;
16 | import java.io.DataOutputStream;
17 | import java.io.IOException;
18 | import java.io.InputStreamReader;
19 | import java.net.URL;
20 | import java.net.URLEncoder;
21 | import java.security.KeyManagementException;
22 | import java.security.KeyStoreException;
23 | import java.security.NoSuchAlgorithmException;
24 |
25 | import javax.net.ssl.HttpsURLConnection;
26 |
27 | import okhttp3.Interceptor;
28 | import okhttp3.Request;
29 | import okhttp3.Response;
30 | import retrofit2.Call;
31 |
32 | public class ConnectUnitTests {
33 | private static String accessToken;
34 | private static String clientId = System.getenv("test_client_id_v1");
35 | private static String username = System.getenv("test_username");
36 | private static String password = System.getenv("test_password");
37 |
38 | private static final String CONTENT_TYPE = "application/x-www-form-urlencoded";
39 | private static final String GRANT_TYPE = "password";
40 | private static final String TOKEN_ENDPOINT = Constants.AUTHORITY_URL + "/oauth2/token";
41 | private static final String REQUEST_METHOD = "POST";
42 |
43 | private final String SUBJECT = "Email sent from test in android connect sample";
44 | private final String BODY = "The body of the test email";
45 |
46 | @BeforeClass
47 | public static void getAccessTokenUsingPasswordGrant() throws IOException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException, JSONException {
48 | URL url = new URL(TOKEN_ENDPOINT);
49 | HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
50 |
51 | String urlParameters = String.format(
52 | "grant_type=%1$s&resource=%2$s&client_id=%3$s&username=%4$s&password=%5$s",
53 | GRANT_TYPE,
54 | URLEncoder.encode(Constants.MICROSOFT_GRAPH_API_ENDPOINT_RESOURCE_ID, "UTF-8"),
55 | clientId,
56 | username,
57 | password
58 | );
59 |
60 | connection.setRequestMethod(REQUEST_METHOD);
61 | connection.setRequestProperty("Content-Type", CONTENT_TYPE);
62 | connection.setRequestProperty("Content-Length", String.valueOf(urlParameters.getBytes("UTF-8").length));
63 |
64 | connection.setDoOutput(true);
65 | DataOutputStream dataOutputStream = new DataOutputStream(connection.getOutputStream());
66 | dataOutputStream.writeBytes(urlParameters);
67 | dataOutputStream.flush();
68 | dataOutputStream.close();
69 |
70 | connection.getResponseCode();
71 |
72 | BufferedReader in = new BufferedReader(
73 | new InputStreamReader(connection.getInputStream()));
74 | String inputLine;
75 | StringBuffer response = new StringBuffer();
76 |
77 | while ((inputLine = in.readLine()) != null) {
78 | response.append(inputLine);
79 | }
80 | in.close();
81 |
82 | JsonParser jsonParser = new JsonParser();
83 | JsonObject grantResponse = (JsonObject)jsonParser.parse(response.toString());
84 | accessToken = grantResponse.get("access_token").getAsString();
85 | }
86 |
87 | @Test
88 | public void sendMail_messageSent() throws IOException {
89 | Interceptor interceptor = new Interceptor() {
90 | @Override
91 | public Response intercept(Chain chain) throws IOException {
92 | Request request = chain.request();
93 | request = request.newBuilder()
94 | .addHeader("Authorization", "Bearer " + accessToken)
95 | // This header has been added to identify this sample in the Microsoft Graph service.
96 | // If you're using this code for your project please remove the following line.
97 | .addHeader("SampleID", "android-java-connect-rest-sample")
98 | .build();
99 |
100 | Response response = chain.proceed(request);
101 | return response;
102 | }
103 | };
104 |
105 | MSGraphAPIController controller = new MSGraphAPIController(interceptor);
106 | Call result = controller.sendMail(username, SUBJECT, BODY);
107 | retrofit2.Response response = result.execute();
108 | Assert.assertTrue("HTTP Response was not successful", response.isSuccessful());
109 | }
110 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.2.1'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoftgraph/android-java-connect-rest-sample/ba07bf5b7304c1e18eccdb5c008450605b696ac7/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Oct 18 10:07:36 PDT 2016
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/oidclib/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/oidclib/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion '23.0.2'
6 |
7 | defaultConfig {
8 | minSdkVersion 9
9 | targetSdkVersion 23
10 | versionCode 2
11 | versionName "1.1"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | compile fileTree(dir: 'libs', include: ['*.jar'])
23 | // For backwards compatibility, not necessarily needed
24 | compile 'com.android.support:appcompat-v7:23.1.1'
25 | compile 'com.android.support:design:23.1.1'
26 |
27 | // Google's OAuth library for OpenID Connect
28 | // See https://code.google.com/p/google-oauth-java-client/wiki/Setup
29 | compile('com.google.oauth-client:google-oauth-client:1.21.0') {
30 | exclude group: 'com.google.http-client', module: 'google-http-client'
31 | exclude group: 'com.google.code.findbugs', module: 'jsr305'
32 | exclude group: 'com.google.http-client', module: 'google-http-client-jackson'
33 | exclude group: 'junit', module: 'junit'
34 | exclude group: 'com.google.guava', module: 'guava-jdk5'
35 | exclude group: 'org.apache.httpcomponents', module: 'httpclient'
36 | }
37 | // Google's JSON parsing, could be replaced with Jackson
38 | compile('com.google.api-client:google-api-client-gson:1.21.0') {
39 | exclude group: 'com.google.api-client', module: 'google-api-client'
40 | exclude group: 'com.google.code.findbugs', module: 'jsr305'
41 | exclude group: 'org.apache.httpcomponents', module: 'httpclient'
42 | }
43 | // For backwards compatibility, not necessarily needed
44 | compile('com.google.api-client:google-api-client-android:1.21.0') {
45 | exclude group: 'com.google.android', module: 'android'
46 | exclude group: 'com.google.code.findbugs', module: 'jsr305'
47 | exclude group: 'com.google.guava', module: 'guava-jdk5'
48 | exclude group: 'junit', module: 'junit'
49 | exclude group: 'org.apache.httpcomponents', module: 'httpclient'
50 | exclude group: 'com.google.http-client', module: 'google-http-client-jackson2'
51 | }
52 |
53 | // Easier HTTP requests, not necessarily needed
54 | compile('com.github.kevinsawicki:http-request:6.0') {
55 | exclude group: 'junit', module: 'junit'
56 | }
57 |
58 | // Encryption for Pre Loli devices
59 | compile 'com.madgag.spongycastle:core:1.54.0.0'
60 | }
61 |
--------------------------------------------------------------------------------
/oidclib/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Applications/Android Studio.app/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | -keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | public *;
17 | }
18 |
19 | # Needed to keep generic types and @Key annotations accessed via reflection
20 | -keepattributes Signature,RuntimeVisibleAnnotations,AnnotationDefault
21 | -keepclassmembers class * {
22 | @com.google.api.client.util.Key ;
23 | }
24 |
25 | # Needed by google-http-client-android when linking against an older platform version
26 | -dontwarn com.google.api.client.extensions.android.**
27 |
28 | # Needed by google-api-client-android when linking against an older platform version
29 | -dontwarn com.google.api.client.googleapis.extensions.android.**
30 |
31 | # Needed by google-play-services when linking against an older platform version
32 | -dontwarn com.google.android.gms.**
33 | -dontnote com.google.android.gms.**
34 |
35 | # com.google.client.util.IOUtils references java.nio.file.Files when on Java 7+
36 | -dontnote java.nio.file.Files, java.nio.file.Path
37 |
38 | # Suppress notes on LicensingServices
39 | -dontnote **.ILicensingService
40 |
41 | # Suppress warnings on sun.misc.Unsafe
42 | -dontnote sun.misc.Unsafe
43 | -dontwarn sun.misc.Unsafe
44 |
--------------------------------------------------------------------------------
/oidclib/src/androidTest/java/com/lnikkila/oidc/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.lnikkila.oidc;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/oidclib/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/oidclib/src/main/assets/Roboto-BoldCondensed.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoftgraph/android-java-connect-rest-sample/ba07bf5b7304c1e18eccdb5c008450605b696ac7/oidclib/src/main/assets/Roboto-BoldCondensed.ttf
--------------------------------------------------------------------------------
/oidclib/src/main/java/com/lnikkila/oidc/OIDCAccountManager.java:
--------------------------------------------------------------------------------
1 | package com.lnikkila.oidc;
2 |
3 | import android.accounts.Account;
4 | import android.accounts.AccountManager;
5 | import android.accounts.AccountManagerCallback;
6 | import android.accounts.AccountManagerFuture;
7 | import android.accounts.AuthenticatorException;
8 | import android.accounts.OperationCanceledException;
9 | import android.app.Activity;
10 | import android.content.Context;
11 | import android.os.Build;
12 | import android.os.Bundle;
13 | import android.util.Log;
14 |
15 | import com.google.api.client.auth.oauth2.TokenResponse;
16 | import com.google.api.client.auth.openidconnect.IdTokenResponse;
17 | import com.google.api.client.util.Preconditions;
18 | import com.lnikkila.oidc.authenticator.Authenticator;
19 | import com.lnikkila.oidc.security.AccountSensitiveDataStorageUtils;
20 | import com.lnikkila.oidc.security.UserNotAuthenticatedWrapperException;
21 |
22 | import java.io.IOException;
23 |
24 | /**
25 | * A layer of syntactic sugar around the AccountManager and the Accounts.
26 | * @author Camilo Montes
27 | * @since 20/01/2016.
28 | */
29 | public class OIDCAccountManager {
30 |
31 | private final String TAG = getClass().getSimpleName();
32 |
33 | private final Context context;
34 | private final AccountManager manager;
35 | private final AccountSensitiveDataStorageUtils secureStorage;
36 |
37 |
38 | public OIDCAccountManager(Context context) {
39 | this.context = Preconditions.checkNotNull(context);
40 | this.manager = AccountManager.get(this.context);
41 | this.secureStorage = new AccountSensitiveDataStorageUtils(context);
42 | }
43 |
44 | public AccountManager getAccountManager() {
45 | return this.manager;
46 | }
47 |
48 | public String getAccountType() {
49 | return context.getString(R.string.account_authenticator_type);
50 | }
51 |
52 | public Account[] getAccounts() {
53 | return this.manager.getAccountsByType(getAccountType());
54 | }
55 |
56 | public Account getAccountByName(String accountName) {
57 | if(accountName != null) {
58 | Account[] accounts = this.getAccounts();
59 | for (Account account : accounts) {
60 | if (accountName.equals(account.name)) {
61 | return account;
62 | }
63 | }
64 | }
65 | return null;
66 | }
67 |
68 | public void createAccount(Activity activity, AccountManagerCallback callback) {
69 | this.manager.addAccount(getAccountType(), Authenticator.TOKEN_TYPE_ID, null, null, activity, callback, null);
70 | }
71 |
72 | public boolean removeAccount(String accountName) {
73 | Account account = getAccountByName(accountName);
74 | return removeAccount(account);
75 | }
76 |
77 | public boolean removeAccount(Account account) {
78 | boolean removed = false;
79 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1){
80 | removed = this.manager.removeAccountExplicitly(account);
81 | }
82 | else {
83 | @SuppressWarnings("deprecation") AccountManagerFuture futureRemoved = this.manager.removeAccount(account, null, null);
84 | try {
85 | removed = futureRemoved.getResult();
86 | } catch (OperationCanceledException | IOException | AuthenticatorException e) {
87 | Log.w("LogoutTask", "Coudln't remove account using pre LOLIPOP remove call");
88 | }
89 | }
90 | return removed;
91 | }
92 |
93 | public boolean isKeyPinRequired() {
94 | boolean keyPinRequired = false;
95 | if (context != null) {
96 | keyPinRequired = context.getResources().getBoolean(R.bool.oidc_encryptKeyAskPin);
97 | }
98 | return keyPinRequired;
99 | }
100 |
101 | public void invalidateAllAccountTokens(Account account) {
102 | if(account != null) {
103 | try {
104 | String idToken = getIdToken(account.name, null);
105 | String accessToken = getAccessToken(account.name, null);
106 | String refreshToken = getRefreshToken(account.name, null);
107 | this.secureStorage.invalidateStringData(this.manager, account, idToken);
108 | this.secureStorage.invalidateStringData(this.manager, account, accessToken);
109 | this.secureStorage.invalidateStringData(this.manager, account, refreshToken);
110 | } catch (AuthenticatorException | UserNotAuthenticatedWrapperException | OperationCanceledException | IOException e) {
111 | Log.w(TAG, String.format("Could not invalidate account %1$s tokens", account.name), e);
112 | }
113 | }
114 | }
115 |
116 | public void invalidateAuthTokens(Account account) {
117 | if(account != null) {
118 | try {
119 | String idToken = getIdToken(account.name, null);
120 | String accessToken = getAccessToken(account.name, null);
121 | this.secureStorage.invalidateStringData(this.manager, account, idToken);
122 | this.secureStorage.invalidateStringData(this.manager, account, accessToken);
123 | } catch (AuthenticatorException | UserNotAuthenticatedWrapperException | OperationCanceledException | IOException e) {
124 | Log.w(TAG, String.format("Could not invalidate account %1$s tokens", account.name), e);
125 | }
126 | }
127 | }
128 |
129 |
130 | public void invalidateAccessToken(Account account) {
131 | if(account != null) {
132 | try {
133 | String accessToken = getAccessToken(account, null);
134 | this.secureStorage.invalidateStringData(this.manager, account, accessToken);
135 | } catch (AuthenticatorException | UserNotAuthenticatedWrapperException | OperationCanceledException | IOException e) {
136 | Log.w(TAG, String.format("Could not invalidate account %1$s AT", account.name), e);
137 | }
138 | }
139 | }
140 |
141 | public String getIdToken(String accountName, AccountManagerCallback callback)
142 | throws AuthenticatorException, UserNotAuthenticatedWrapperException, OperationCanceledException, IOException {
143 | return getToken(accountName, Authenticator.TOKEN_TYPE_ID, callback);
144 | }
145 |
146 | public String getAccessToken(Account account, AccountManagerCallback callback)
147 | throws AuthenticatorException, UserNotAuthenticatedWrapperException, OperationCanceledException, IOException {
148 | return getToken(account, Authenticator.TOKEN_TYPE_ACCESS, callback);
149 | }
150 |
151 | public String getAccessToken(String accountName, AccountManagerCallback callback)
152 | throws AuthenticatorException, UserNotAuthenticatedWrapperException, OperationCanceledException, IOException {
153 | return getToken(accountName, Authenticator.TOKEN_TYPE_ACCESS, callback);
154 | }
155 |
156 | public String getRefreshToken(String accountName, AccountManagerCallback callback)
157 | throws AuthenticatorException, UserNotAuthenticatedWrapperException, OperationCanceledException, IOException {
158 | return getToken(accountName, Authenticator.TOKEN_TYPE_REFRESH, callback);
159 | }
160 |
161 | private String getToken(String accountName, String tokenType, AccountManagerCallback callback)
162 | throws AuthenticatorException, UserNotAuthenticatedWrapperException, OperationCanceledException, IOException {
163 | Account account = getAccountByName(accountName);
164 | return getToken(account, tokenType, callback);
165 | }
166 |
167 | private String getToken(Account account, String tokenType, AccountManagerCallback callback)
168 | throws AuthenticatorException, UserNotAuthenticatedWrapperException, OperationCanceledException, IOException {
169 | return this.secureStorage.retrieveStringData(this.manager, account, tokenType, callback);
170 | }
171 |
172 | public void saveTokens(Account account, TokenResponse tokenResponse) throws UserNotAuthenticatedWrapperException {
173 | if (tokenResponse instanceof IdTokenResponse) {
174 | saveToken(account, Authenticator.TOKEN_TYPE_ID, ((IdTokenResponse) tokenResponse).getIdToken());
175 | }
176 | saveToken(account, Authenticator.TOKEN_TYPE_ACCESS, tokenResponse.getAccessToken());
177 | saveToken(account, Authenticator.TOKEN_TYPE_REFRESH, tokenResponse.getRefreshToken());
178 | }
179 |
180 | public void saveTokens(String accountName, TokenResponse tokenResponse) throws UserNotAuthenticatedWrapperException {
181 | if (tokenResponse instanceof IdTokenResponse) {
182 | saveToken(accountName, Authenticator.TOKEN_TYPE_ID, ((IdTokenResponse)tokenResponse).getIdToken());
183 | }
184 | saveToken(accountName, Authenticator.TOKEN_TYPE_ACCESS, tokenResponse.getAccessToken());
185 | saveToken(accountName, Authenticator.TOKEN_TYPE_REFRESH, tokenResponse.getRefreshToken());
186 | }
187 |
188 | private void saveToken(String accountName, String tokenType, String token) throws UserNotAuthenticatedWrapperException {
189 | Account account = getAccountByName(accountName);
190 | saveToken(account, tokenType, token);
191 | }
192 |
193 | private void saveToken(Account account, String tokenType, String token) throws UserNotAuthenticatedWrapperException {
194 | this.secureStorage.storeStringData(this.manager, account, tokenType, token);
195 | }
196 | }
197 |
--------------------------------------------------------------------------------
/oidclib/src/main/java/com/lnikkila/oidc/authenticator/Authenticator.java:
--------------------------------------------------------------------------------
1 | package com.lnikkila.oidc.authenticator;
2 |
3 | import android.accounts.AbstractAccountAuthenticator;
4 | import android.accounts.Account;
5 | import android.accounts.AccountAuthenticatorResponse;
6 | import android.accounts.AccountManager;
7 | import android.accounts.NetworkErrorException;
8 | import android.content.Context;
9 | import android.content.Intent;
10 | import android.os.Bundle;
11 | import android.text.TextUtils;
12 | import android.util.Log;
13 |
14 | import com.google.api.client.auth.oauth2.TokenResponse;
15 | import com.google.api.client.auth.oauth2.TokenResponseException;
16 | import com.lnikkila.oidc.OIDCAccountManager;
17 | import com.lnikkila.oidc.OIDCRequestManager;
18 | import com.lnikkila.oidc.security.UserNotAuthenticatedWrapperException;
19 |
20 | import java.io.IOException;
21 |
22 | import static java.net.HttpURLConnection.HTTP_BAD_REQUEST;
23 |
24 | /**
25 | * Used by Android's AccountManager to manage our account information.
26 | *
27 | * The three OpenID tokens (not counting the single-use Authorization Token that is discarded) are
28 | * stored as what Android calls "auth tokens". They all have different token types:
29 | *
30 | * ID Token: TOKEN_TYPE_ID
31 | * Access Token: TOKEN_TYPE_ACCESS (replaceable by the ID Token, so we're not really using this)
32 | * Refresh Token: TOKEN_TYPE_REFRESH
33 | *
34 | * @author Leo Nikkilä
35 | * @author Camilo Montes
36 | */
37 | public class Authenticator extends AbstractAccountAuthenticator {
38 |
39 | private final String TAG = getClass().getSimpleName();
40 |
41 | protected final Context context;
42 | protected final OIDCAccountManager accountManager;
43 | protected final OIDCRequestManager requestManager;
44 |
45 | public static final String TOKEN_TYPE_ID = "com.lnikkila.oidcsample.TOKEN_TYPE_ID";
46 | public static final String TOKEN_TYPE_ACCESS = "com.lnikkila.oidcsample.TOKEN_TYPE_ACCESS";
47 | public static final String TOKEN_TYPE_REFRESH = "com.lnikkila.oidcsample.TOKEN_TYPE_REFRESH";
48 |
49 | public Authenticator(Context context) {
50 | super(context);
51 | this.context = context;
52 |
53 | this.accountManager = new OIDCAccountManager(context);
54 | this.requestManager = new OIDCRequestManager(context);
55 |
56 | Log.d(TAG, "Authenticator created.");
57 | }
58 |
59 | //region Methods implemented from AbstractAccountAuthenticator
60 |
61 | /**
62 | * Called when the user adds a new account through Android's system settings or when an app
63 | * explicitly calls this.
64 | */
65 | @Override
66 | public Bundle addAccount(AccountAuthenticatorResponse response, String accountType,
67 | String authTokenType, String[] requiredFeatures, Bundle options) {
68 |
69 | Log.d(TAG, String.format("addAccount called with accountType %s, authTokenType %s.",
70 | accountType, authTokenType));
71 |
72 | Bundle result = new Bundle();
73 |
74 | Intent intent = createIntentForAuthorization(response);
75 |
76 | // We're creating a new account, not just renewing our authorisation
77 | intent.putExtra(AuthenticatorActivity.KEY_IS_NEW_ACCOUNT, true);
78 |
79 | result.putParcelable(AccountManager.KEY_INTENT, intent);
80 |
81 | return result;
82 | }
83 |
84 | /**
85 | * Tries to retrieve a previously stored token of any type. If the token doesn't exist yet or
86 | * has been invalidated, we need to request a set of replacement tokens.
87 | */
88 | @Override
89 | public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account,
90 | String authTokenType, Bundle options) {
91 |
92 | Log.d(TAG, String.format("getAuthToken called with account.type '%s', account.name '%s', " +
93 | "authTokenType '%s'.", account.type, account.name, authTokenType));
94 |
95 | // Try to retrieve a stored token
96 | String token = accountManager.getAccountManager().peekAuthToken(account, authTokenType);
97 |
98 | if (TextUtils.isEmpty(token)) {
99 | // If we don't have one or the token has been invalidated, we need to check if we have
100 | // a refresh token
101 | Log.d(TAG, "Token empty, checking for refresh token.");
102 | String refreshToken = accountManager.getAccountManager().peekAuthToken(account, TOKEN_TYPE_REFRESH);
103 |
104 | if (TextUtils.isEmpty(refreshToken)) {
105 | // If we don't even have a refresh token, we need to launch an intent for the user
106 | // to get us a new set of tokens by authorising us again.
107 |
108 | Log.d(TAG, "Refresh token empty, launching intent for renewing authorisation.");
109 |
110 | Bundle result = new Bundle();
111 |
112 | Intent intent = createIntentForAuthorization(response);
113 |
114 | // Provide the account that we need re-authorised
115 | intent.putExtra(AuthenticatorActivity.KEY_ACCOUNT_NAME, account.name);
116 |
117 | result.putParcelable(AccountManager.KEY_INTENT, intent);
118 | return result;
119 | } else {
120 | // Got a refresh token, let's use it to get a fresh set of tokens
121 | Log.d(TAG, "Got refresh token, getting new tokens.");
122 |
123 | try {
124 | refreshTokens(account, refreshToken);
125 | }
126 | catch (TokenResponseException e) {
127 | // If the refresh token has expired, we need to launch an intent for the user
128 | // to get us a new set of tokens by authorising us again.
129 |
130 | Log.d(TAG, "Refresh token expired, launching intent for renewing authorisation.");
131 |
132 | Bundle result = new Bundle();
133 |
134 | Intent intent = createIntentForAuthorization(response);
135 |
136 | // Provide the account that we need re-authorised
137 | intent.putExtra(AuthenticatorActivity.KEY_ACCOUNT_NAME, account.name);
138 |
139 | result.putParcelable(AccountManager.KEY_INTENT, intent);
140 | return result;
141 | } catch (UserNotAuthenticatedWrapperException e) {
142 | //FIXME: we need to see how to handle this here because we can't do a start activity for result
143 | }
144 |
145 | // Now, let's return the token that was requested
146 | token = accountManager.getAccountManager().peekAuthToken(account, authTokenType);
147 | }
148 | }
149 |
150 | Log.d(TAG, String.format("Returning token '%s' of type '%s'.", token, authTokenType));
151 |
152 | Bundle result = new Bundle();
153 |
154 | result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
155 | result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
156 | result.putString(AccountManager.KEY_AUTHTOKEN, token);
157 |
158 | return result;
159 | }
160 |
161 | /**
162 | * Refreshes all account tokens by requesting new tokens to the access_token endpoint using the given refreshToken.
163 | * @param account the account whose token should be refreshed, will never be null
164 | * @param refreshToken the refresh token to be use
165 | * @throws TokenResponseException when refreshToken is invalid or expired
166 | */
167 | protected void refreshTokens(Account account, String refreshToken) throws TokenResponseException, UserNotAuthenticatedWrapperException {
168 | try {
169 | TokenResponse tokenResponse = requestManager.refreshTokens(refreshToken);
170 | Log.d(TAG, "Got new tokens.");
171 | accountManager.saveTokens(account, tokenResponse);
172 | } catch (TokenResponseException e) {
173 | //If token has expired propagate the exception, else just treat it like an IOException
174 | if(e.getStatusCode() == HTTP_BAD_REQUEST && e.getContent().contains("invalid_grant")) {
175 | Log.d(TAG, "Refresh token expired response detected");
176 | throw e; //TODO: maybe we should make a custom exception class to handle this?
177 | } else {
178 | // There's not much we can do if we get here
179 | Log.e(TAG, "Couldn't get new tokens.", e);
180 | }
181 | } catch (IOException e) {
182 | // There's not much we can do if we get here
183 | Log.e(TAG, "Couldn't get new tokens.", e);
184 | }
185 | }
186 |
187 | //endregion
188 |
189 | //region Methods NOT implemented from AbstractAccountAuthenticator
190 |
191 | @Override
192 | public String getAuthTokenLabel(String authTokenType) {
193 | return null;
194 | }
195 |
196 | @Override
197 | public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account,
198 | String[] features) throws NetworkErrorException {
199 | return null;
200 | }
201 |
202 | @Override
203 | public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
204 | return null;
205 | }
206 |
207 | @Override
208 | public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account,
209 | Bundle options) throws NetworkErrorException {
210 | return null;
211 | }
212 |
213 | @Override
214 | public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account,
215 | String authTokenType, Bundle options)
216 | throws NetworkErrorException {
217 | return null;
218 | }
219 |
220 | //endregion
221 |
222 | /**
223 | * Create an intent for showing the authorisation web page.
224 | * @param response response to send the result back to the AccountManager, will never be null
225 | * @return an intent to open AuthenticatorActivity with AuthenticatorActivity.KEY_PRESENT_OPTS_FORM extra
226 | * set to false if OIDC client correctly options are set (true otherwise).
227 | */
228 | protected Intent createIntentForAuthorization(AccountAuthenticatorResponse response) {
229 | Intent intent = new Intent(context, AuthenticatorActivity.class);
230 | intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
231 | return intent;
232 | }
233 |
234 | }
235 |
--------------------------------------------------------------------------------
/oidclib/src/main/java/com/lnikkila/oidc/authenticator/AuthenticatorService.java:
--------------------------------------------------------------------------------
1 | package com.lnikkila.oidc.authenticator;
2 |
3 | import android.app.Service;
4 | import android.content.Intent;
5 | import android.os.IBinder;
6 | import android.util.Log;
7 |
8 | /**
9 | * The service that lets Android know about the custom Authenticator.
10 | *
11 | * @author Leo Nikkilä
12 | */
13 | public class AuthenticatorService extends Service {
14 |
15 | private final String TAG = getClass().getSimpleName();
16 |
17 | @Override
18 | public IBinder onBind(Intent intent) {
19 | Log.d(TAG, "Binding Authenticator.");
20 |
21 | Authenticator authenticator = new Authenticator(this);
22 | return authenticator.getIBinder();
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/oidclib/src/main/java/com/lnikkila/oidc/minsdkcompat/CompatEditText.java:
--------------------------------------------------------------------------------
1 | package com.lnikkila.oidc.minsdkcompat;
2 |
3 | import android.content.Context;
4 | import android.graphics.Typeface;
5 | import android.support.v7.widget.AppCompatEditText;
6 | import android.util.AttributeSet;
7 |
8 | /**
9 | *
10 | * @author Camilo Montes
11 | */
12 | public class CompatEditText extends AppCompatEditText {
13 |
14 | public CompatEditText(Context context, AttributeSet attrs, int defStyle) {
15 | super(context, attrs, defStyle);
16 | createFont();
17 | }
18 |
19 | public CompatEditText(Context context, AttributeSet attrs) {
20 | super(context, attrs);
21 | createFont();
22 | }
23 |
24 | public CompatEditText(Context context) {
25 | super(context);
26 | createFont();
27 | }
28 |
29 | public void createFont() {
30 | Typeface font = Typeface.createFromAsset(getContext().getAssets(), "Roboto-BoldCondensed.ttf");
31 | setTypeface(font);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/oidclib/src/main/java/com/lnikkila/oidc/minsdkcompat/CompatTextView.java:
--------------------------------------------------------------------------------
1 | package com.lnikkila.oidc.minsdkcompat;
2 |
3 | import android.content.Context;
4 | import android.graphics.Typeface;
5 | import android.support.v7.widget.AppCompatTextView;
6 | import android.util.AttributeSet;
7 | import android.widget.TextView;
8 |
9 | /**
10 | *
11 | * @author Camilo Montes
12 | */
13 | public class CompatTextView extends AppCompatTextView {
14 | public CompatTextView(Context context, AttributeSet attrs, int defStyle) {
15 | super(context, attrs, defStyle);
16 | createFont();
17 | }
18 |
19 | public CompatTextView(Context context, AttributeSet attrs) {
20 | super(context, attrs);
21 | createFont();
22 | }
23 |
24 | public CompatTextView(Context context) {
25 | super(context);
26 | createFont();
27 | }
28 |
29 | public void createFont() {
30 | Typeface font = Typeface.createFromAsset(getContext().getAssets(), "Roboto-BoldCondensed.ttf");
31 | setTypeface(font);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/oidclib/src/main/java/com/lnikkila/oidc/minsdkcompat/CompatUri.java:
--------------------------------------------------------------------------------
1 | package com.lnikkila.oidc.minsdkcompat;
2 |
3 | import android.annotation.TargetApi;
4 | import android.net.Uri;
5 | import android.os.Build;
6 |
7 | import java.util.Collections;
8 | import java.util.LinkedHashSet;
9 | import java.util.Set;
10 |
11 | /**
12 | * Created by CQX342 on 12/06/2015.
13 | * @see "http://stackoverflow.com/a/12081355"
14 | */
15 | public class CompatUri {
16 | /**
17 | * Error message presented when a user tries to treat an opaque URI as
18 | * hierarchical.
19 | */
20 | private static final String NOT_HIERARCHICAL
21 | = "This isn't a hierarchical URI.";
22 |
23 | /**
24 | * Returns a set of the unique names of all query parameters. Iterating
25 | * over the set will return the names in order of their first occurrence.
26 | * Extracted from Uri#getQueryParameterNames() API 22.
27 | *
28 | * @throws UnsupportedOperationException if this isn't a hierarchical URI
29 | * @see Uri#getQueryParameterNames()
30 | *
31 | * @return a set of decoded names
32 | */
33 | @TargetApi(Build.VERSION_CODES.GINGERBREAD)
34 | public static Set getQueryParameterNames(Uri uri) {
35 | if (uri.isOpaque()) {
36 | throw new UnsupportedOperationException(NOT_HIERARCHICAL);
37 | }
38 |
39 | String query = uri.getEncodedQuery();
40 | if (query == null) {
41 | return Collections.emptySet();
42 | }
43 |
44 | Set names = new LinkedHashSet<>();
45 | int start = 0;
46 | do {
47 | int next = query.indexOf('&', start);
48 | int end = (next == -1) ? query.length() : next;
49 |
50 | int separator = query.indexOf('=', start);
51 | if (separator > end || separator == -1) {
52 | separator = end;
53 | }
54 |
55 | String name = query.substring(start, separator);
56 | names.add(Uri.decode(name));
57 |
58 | // Move start to end of name.
59 | start = end + 1;
60 | } while (start < query.length());
61 |
62 | return Collections.unmodifiableSet(names);
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/oidclib/src/main/java/com/lnikkila/oidc/security/AccountSensitiveDataStorageUtils.java:
--------------------------------------------------------------------------------
1 | package com.lnikkila.oidc.security;
2 |
3 | import android.accounts.Account;
4 | import android.accounts.AccountManager;
5 | import android.accounts.AccountManagerCallback;
6 | import android.accounts.AccountManagerFuture;
7 | import android.accounts.AuthenticatorException;
8 | import android.accounts.OperationCanceledException;
9 | import android.content.Context;
10 | import android.os.Build;
11 | import android.os.Bundle;
12 |
13 | import java.io.IOException;
14 |
15 | /**
16 | * Created by Camilo Montes on 18/01/2016.
17 | * Copyright LaPoste
18 | */
19 | public class AccountSensitiveDataStorageUtils {
20 |
21 | private final static boolean SHOW_NOTIF_ON_AUTHFAILURE = true;
22 | private SensitiveDataUtils dataEncUtils;
23 |
24 | public AccountSensitiveDataStorageUtils(Context context) {
25 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
26 | dataEncUtils = new SensitiveDataPreApi23(context);
27 | } else {
28 | dataEncUtils = new SensitiveDataPostApi23(context);
29 | }
30 | }
31 |
32 | /**
33 | * Get the stored data from a secure store, decrypting the data if needed.
34 | * @return The data store on the secure storage.
35 | */
36 | public String retrieveStringData(AccountManager accountManager, Account account, String tokenType, AccountManagerCallback callback)
37 | throws UserNotAuthenticatedWrapperException, AuthenticatorException, OperationCanceledException, IOException {
38 | String data = null;
39 |
40 | // Try retrieving an access token from the account manager. The boolean #SHOW_NOTIF_ON_AUTHFAILURE in the invocation
41 | // tells Android to show a notification if the token can't be retrieved. When the
42 | // notification is selected, it will launch the intent for re-authorisation. You could
43 | // launch it automatically here if you wanted to by grabbing the intent from the bundle.
44 | AccountManagerFuture futureManager;
45 |
46 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
47 | //noinspection deprecation
48 | futureManager = accountManager.getAuthToken(
49 | account,
50 | tokenType,
51 | SHOW_NOTIF_ON_AUTHFAILURE,
52 | callback,
53 | null);
54 | }
55 | else {
56 | futureManager = accountManager.getAuthToken(
57 | account,
58 | tokenType,
59 | null,
60 | SHOW_NOTIF_ON_AUTHFAILURE,
61 | callback,
62 | null);
63 | }
64 | String encryptedToken = futureManager.getResult().getString(AccountManager.KEY_AUTHTOKEN);
65 | if (encryptedToken != null) {
66 | data = dataEncUtils.decrypt(encryptedToken);
67 | }
68 |
69 | return data;
70 | }
71 |
72 | /**
73 | * Store the given serialized data onto a secure store, encrypting the data if needed.
74 | * @param data The data to store securely
75 | * @return true if the data was store, false otherwise.
76 | */
77 | public boolean storeStringData(AccountManager accountManager, Account account, String tokenType, String data) throws UserNotAuthenticatedWrapperException {
78 | accountManager.setAuthToken(account, tokenType, dataEncUtils.encrypt(data));
79 | return true;
80 | }
81 |
82 | public void invalidateStringData(AccountManager accountManager, Account account, String data) throws UserNotAuthenticatedWrapperException {
83 | accountManager.invalidateAuthToken(account.type, dataEncUtils.encrypt(data));
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/oidclib/src/main/java/com/lnikkila/oidc/security/SensitiveDataPostApi23.java:
--------------------------------------------------------------------------------
1 | package com.lnikkila.oidc.security;
2 |
3 | import android.annotation.TargetApi;
4 | import android.app.Activity;
5 | import android.content.Context;
6 | import android.content.SharedPreferences;
7 | import android.os.Build;
8 | import android.security.keystore.KeyGenParameterSpec;
9 | import android.security.keystore.KeyProperties;
10 | import android.security.keystore.UserNotAuthenticatedException;
11 | import android.util.Base64;
12 | import android.util.Log;
13 |
14 | import com.lnikkila.oidc.R;
15 |
16 | import java.io.IOException;
17 | import java.security.InvalidAlgorithmParameterException;
18 | import java.security.InvalidKeyException;
19 | import java.security.KeyStore;
20 | import java.security.KeyStoreException;
21 | import java.security.NoSuchAlgorithmException;
22 | import java.security.NoSuchProviderException;
23 | import java.security.UnrecoverableEntryException;
24 | import java.security.cert.CertificateException;
25 |
26 | import javax.crypto.BadPaddingException;
27 | import javax.crypto.Cipher;
28 | import javax.crypto.IllegalBlockSizeException;
29 | import javax.crypto.KeyGenerator;
30 | import javax.crypto.NoSuchPaddingException;
31 | import javax.crypto.SecretKey;
32 | import javax.crypto.spec.IvParameterSpec;
33 |
34 | /**
35 | * For post {@link Build.VERSION_CODES#M } data encryption.
36 | * Uses AndroidKeyStore
37 | * Created by Camilo Montes on 14/10/2015.
38 | * @see https://github.com/Zlate87/android-fingerprint-example/blob/master/app/src/main/java/com/example/zlatko/fingerprintexample/MainActivity.java
39 | */
40 | @TargetApi(Build.VERSION_CODES.M)
41 | public class SensitiveDataPostApi23 extends SensitiveDataUtils {
42 |
43 | //region Constants
44 |
45 | protected static final String KEYSTORE_TYPE = "AndroidKeyStore";
46 |
47 | protected static final String CIPHER_BLOCKS = KeyProperties.BLOCK_MODE_CBC;
48 | protected static final String CIPHER_PADDING = KeyProperties.ENCRYPTION_PADDING_PKCS7;
49 |
50 | protected static final String IV_STORAGE_FILE_NAME = "ivStorage";
51 | protected static final String IV_PARAM_KEY = "ivEncryption";
52 |
53 | protected static final String DEFAULT_KEY_ALIAS = "OIDCEncKey";
54 | protected static final boolean DEFAULT_REQUIRED_PIN = false;
55 | protected static final int DEFAULT_KEYPIN_DURATION = 5*60;
56 |
57 | //endregion
58 |
59 | private KeyStore keyStore;
60 | private Cipher encryptCipher;
61 |
62 | public SensitiveDataPostApi23(Context context) {
63 | super(context);
64 | try {
65 | encryptCipher = Cipher.getInstance(String.format("%1$s/%2$s/%3$s", CIPHER_ALGO, CIPHER_BLOCKS, CIPHER_PADDING));
66 | } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
67 | throw new RuntimeException(e);
68 | }
69 | }
70 |
71 | private String getKeyAlias() {
72 | String keyAlias = DEFAULT_KEY_ALIAS;
73 | if (context.get() != null) {
74 | keyAlias = context.get().getString(R.string.oidc_encryptKeyAlias);
75 | keyAlias = keyAlias.isEmpty() ? DEFAULT_KEY_ALIAS : keyAlias;
76 | }
77 | return keyAlias;
78 | }
79 |
80 | public boolean isKeyPinRequired() {
81 | boolean encryptKeyPinRequired = DEFAULT_REQUIRED_PIN;
82 | if (context.get() != null) {
83 | encryptKeyPinRequired = context.get().getResources().getBoolean(R.bool.oidc_encryptKeyAskPin);
84 | }
85 | return encryptKeyPinRequired;
86 | }
87 |
88 | private int getKeyPinDuration() {
89 | int encryptKeyPinDuration = DEFAULT_KEYPIN_DURATION;
90 | if (context.get() != null) {
91 | encryptKeyPinDuration = context.get().getResources().getInteger(R.integer.oidc_encryptKeyPinDuration);
92 | encryptKeyPinDuration = encryptKeyPinDuration <= 0 ? DEFAULT_KEYPIN_DURATION : encryptKeyPinDuration;
93 | }
94 | return encryptKeyPinDuration;
95 | }
96 |
97 | //region SensitiveDataUtils implementation
98 |
99 | protected void createAndSaveSecretKey() {
100 | try {
101 | keyStore = KeyStore.getInstance(KEYSTORE_TYPE);
102 | keyStore.load(null);
103 |
104 | KeyStore.SecretKeyEntry entry = (KeyStore.SecretKeyEntry)keyStore.getEntry(getKeyAlias(), null);
105 | if (entry == null) {
106 | generateKey();
107 | }
108 | } catch (KeyStoreException | CertificateException | IOException | NoSuchAlgorithmException e) {
109 | Log.e(TAG, "Couldn't get a reference to the AndroidKeyStore", e);
110 | } catch (UnrecoverableEntryException e) {
111 | Log.e(TAG, "Couldn't extract key from the AndroidKeyStore", e);
112 | }
113 | }
114 |
115 | protected SecretKey generateKey() {
116 | SecretKey key = null;
117 | try {
118 | KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(
119 | getKeyAlias(),
120 | KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT);
121 |
122 | KeyGenParameterSpec keySpec = builder
123 | .setKeySize(CIPHER_KEY_LENGHT)
124 | .setBlockModes(CIPHER_BLOCKS)
125 | .setEncryptionPaddings(CIPHER_PADDING)
126 | .setRandomizedEncryptionRequired(false) //FIXME: set to true because we should be using IND-CPA but this means that a IV has to be store per token (less generic than i though)
127 | .setUserAuthenticationRequired(isKeyPinRequired())
128 | .setUserAuthenticationValidityDurationSeconds(getKeyPinDuration())
129 | .build();
130 |
131 | KeyGenerator kg = KeyGenerator.getInstance(CIPHER_ALGO, KEYSTORE_TYPE);
132 | kg.init(keySpec);
133 | key = kg.generateKey();
134 | } catch (InvalidAlgorithmParameterException | NoSuchProviderException | NoSuchAlgorithmException e) {
135 | Log.e(TAG, "Couldn't generate secret key", e);
136 | }
137 | return key;
138 | }
139 |
140 | protected void initCipher(boolean forEncryption) throws UnrecoverableEntryException, NoSuchAlgorithmException, KeyStoreException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
141 | KeyStore.SecretKeyEntry entry = (KeyStore.SecretKeyEntry)keyStore.getEntry(getKeyAlias(), null);
142 | SecretKey key = entry.getSecretKey();
143 | SharedPreferences sharedPreferences = context.get().getSharedPreferences(IV_STORAGE_FILE_NAME, Activity.MODE_PRIVATE);
144 | String base64EncryptionIv = sharedPreferences.getString(IV_PARAM_KEY, null);
145 |
146 | if(forEncryption) {
147 | if (base64EncryptionIv == null) {
148 | encryptCipher.init(Cipher.ENCRYPT_MODE, key);
149 |
150 | byte[] encryptionIV = encryptCipher.getIV();
151 | base64EncryptionIv = Base64.encodeToString(encryptionIV, Base64.DEFAULT);
152 |
153 | SharedPreferences.Editor editor = sharedPreferences.edit();
154 | editor.putString(IV_PARAM_KEY, base64EncryptionIv);
155 | editor.apply();
156 | } else {
157 | byte[] encryptionIv = Base64.decode(base64EncryptionIv, Base64.DEFAULT);
158 | encryptCipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(encryptionIv)); //FIXME: this ain't good, and we are re-using the same IV (security guidelines say we shouldn't)
159 | }
160 | } else {
161 | byte[] encryptionIv = Base64.decode(base64EncryptionIv, Base64.DEFAULT);
162 |
163 | encryptCipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(encryptionIv));
164 | }
165 | }
166 |
167 | protected byte[] encrypt(byte[] data) throws UserNotAuthenticatedWrapperException {
168 | byte[] encrypted;
169 | try {
170 | initCipher(true);
171 | encrypted = encryptCipher.doFinal(data);
172 | } catch (UserNotAuthenticatedException e) {
173 | throw new UserNotAuthenticatedWrapperException(e);
174 | } catch (NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException |
175 | InvalidKeyException | BadPaddingException | UnrecoverableEntryException | KeyStoreException | InvalidAlgorithmParameterException e) {
176 | throw new RuntimeException(e);
177 | }
178 | return encrypted;
179 | }
180 |
181 | protected byte[] decrypt(byte[] data) throws UserNotAuthenticatedWrapperException {
182 | byte[] decrypted;
183 | try {
184 | initCipher(false);
185 | decrypted = encryptCipher.doFinal(data);
186 | } catch (UserNotAuthenticatedException e) {
187 | throw new UserNotAuthenticatedWrapperException(e);
188 | } catch (NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException | InvalidKeyException |
189 | BadPaddingException | UnrecoverableEntryException | KeyStoreException | InvalidAlgorithmParameterException e) {
190 | throw new RuntimeException(e);
191 | }
192 | return decrypted;
193 | }
194 |
195 | //endregion
196 | }
197 |
--------------------------------------------------------------------------------
/oidclib/src/main/java/com/lnikkila/oidc/security/SensitiveDataPreApi23.java:
--------------------------------------------------------------------------------
1 | package com.lnikkila.oidc.security;
2 |
3 | import android.content.Context;
4 | import android.util.Log;
5 |
6 | import com.lnikkila.oidc.R;
7 |
8 | import org.spongycastle.crypto.InvalidCipherTextException;
9 | import org.spongycastle.crypto.engines.AESFastEngine;
10 | import org.spongycastle.crypto.modes.CBCBlockCipher;
11 | import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
12 | import org.spongycastle.crypto.params.KeyParameter;
13 | import org.spongycastle.crypto.params.ParametersWithIV;
14 | import org.spongycastle.util.Arrays;
15 |
16 | import java.io.FileInputStream;
17 | import java.io.FileNotFoundException;
18 | import java.io.FileOutputStream;
19 | import java.io.IOException;
20 | import java.security.NoSuchAlgorithmException;
21 | import java.security.SecureRandom;
22 |
23 | import javax.crypto.KeyGenerator;
24 | import javax.crypto.SecretKey;
25 | import javax.crypto.spec.SecretKeySpec;
26 |
27 | /**
28 | * For pre {@link android.os.Build.VERSION_CODES#M } data encryption.
29 | * Uses Spongy Castle
30 | * Created by Camilo Montes on 18/01/2016.
31 | */
32 | public class SensitiveDataPreApi23 extends SensitiveDataUtils {
33 |
34 | //region Constants
35 |
36 | private static final String DEFAULT_KEYSTORE_PATH = "oidc_enc_key";
37 |
38 | //endregion
39 |
40 | public SensitiveDataPreApi23(Context context) {
41 | super(context);
42 | }
43 |
44 | private String getKeyStorePath() {
45 | String keyAlias = DEFAULT_KEYSTORE_PATH;
46 | if (context.get() != null) {
47 | keyAlias = context.get().getString(R.string.oidc_encryptKeyAlias);
48 | keyAlias = keyAlias.isEmpty() ? DEFAULT_KEYSTORE_PATH : keyAlias;
49 | }
50 | return keyAlias;
51 | }
52 |
53 | /**
54 | * Write the given data to private storage
55 | * @param data The data to store
56 | * @param filename The filename to store the data in
57 | */
58 | private void saveKey(byte[] data, String filename) {
59 | try {
60 | Context mContext = context.get();
61 | if (mContext != null) {
62 | FileOutputStream fOut = mContext.openFileOutput(filename, Context.MODE_PRIVATE);
63 | fOut.write(data);
64 | fOut.flush();
65 | fOut.close();
66 | } else {
67 | Log.e(TAG, "Can't save the encryption key, application context is null");
68 | }
69 | } catch (IOException e) {
70 | Log.e(TAG, "Can't save the encryption key", e);
71 | }
72 | }
73 |
74 | /**
75 | * Read data from private storage using the given filename
76 | * @param filename The filename whose contents to read
77 | * @return The contents of the file or null
78 | * @throws IOException
79 | */
80 | private byte[] loadKey(String filename) throws IOException {
81 | byte[] key2 = null;
82 | try
83 | {
84 | Context mContext = context.get();
85 | if (mContext != null) {
86 | byte[] key = new byte[5096];
87 | Arrays.fill(key, (byte) 0);
88 | FileInputStream fOut = mContext.openFileInput(filename);
89 | int length = fOut.read(key);
90 | key2 = new byte[length];
91 | System.arraycopy(key, 0, key2, 0, length);
92 | fOut.close();
93 | } else {
94 | Log.e(TAG, "Can't load the encryption key, application context is null");
95 | }
96 | } catch(FileNotFoundException e) {
97 | Log.e(TAG, "Can't load the encryption key", e);
98 | }
99 | return key2;
100 | }
101 |
102 | /**
103 | * Saves the given secret key to private storage
104 | * @param key the key to store
105 | * @see #saveKey(byte[], String)
106 | */
107 | private void saveKey(SecretKey key) {
108 | saveKey(key.getEncoded(), getKeyStorePath());
109 | }
110 |
111 | /**
112 | * Reads the secret key from private storage
113 | * @return the secret key
114 | * @see #loadKey(String)
115 | */
116 | private SecretKey loadKey() {
117 | SecretKey secretKey = null;
118 | try {
119 | byte[] keyBytes = loadKey(getKeyStorePath()); // Hard-coded filename representing the encryption key
120 | secretKey = new SecretKeySpec(keyBytes, 0, keyBytes.length, CIPHER_ALGO);
121 | }
122 | catch (IOException | IllegalArgumentException e) {
123 | Log.e(TAG, String.format("Can't read key from storage at %1$s", getKeyStorePath()), e);
124 | }
125 | return secretKey;
126 | }
127 |
128 | private byte[] cipherData(PaddedBufferedBlockCipher cipher, byte[] data) throws InvalidCipherTextException {
129 | int minSize = cipher.getOutputSize(data.length);
130 | byte[] outBuf = new byte[minSize];
131 | int length1 = cipher.processBytes(data, 0, data.length, outBuf, 0);
132 | int length2 = cipher.doFinal(outBuf, length1);
133 | int actualLength = length1 + length2;
134 | byte[] result = new byte[actualLength];
135 | System.arraycopy(outBuf, 0, result, 0, result.length);
136 | return result;
137 | }
138 |
139 | // region SensitiveDataUtils implementation
140 |
141 | protected void createAndSaveSecretKey() {
142 | SecretKey key = generateKey();
143 | saveKey(key);
144 | }
145 |
146 | protected SecretKey generateKey() {
147 | SecretKey key = null;
148 | try {
149 | KeyGenerator keyGenerator = KeyGenerator.getInstance(CIPHER_ALGO);
150 | keyGenerator.init(CIPHER_KEY_LENGHT);
151 | key = keyGenerator.generateKey();
152 | } catch( NoSuchAlgorithmException e) {
153 | Log.e(TAG, "Could not create secret key", e);
154 | }
155 | return key;
156 | }
157 |
158 | protected byte[] encrypt(byte[] data) {
159 | // 16 bytes is the IV size for AES256
160 | try {
161 | SecretKey key = loadKey();
162 |
163 | // Random IV
164 | SecureRandom rng = new SecureRandom();
165 | byte[] ivBytes = new byte[16]; // 16 bytes is the IV size for AES256
166 | rng.nextBytes(ivBytes);
167 |
168 | PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESFastEngine()));
169 | cipher.init(true, new ParametersWithIV(new KeyParameter(key.getEncoded()), ivBytes));
170 |
171 | byte[] encryptedData = cipherData(cipher, data);
172 | byte[] encryptedDataWithIV = new byte[encryptedData.length + ivBytes.length]; // Make room for IV
173 | System.arraycopy(ivBytes, 0, encryptedDataWithIV, 0, ivBytes.length); // Add IV
174 | System.arraycopy(encryptedData, 0, encryptedDataWithIV, ivBytes.length, encryptedData.length); // Then the encrypted data
175 | return encryptedDataWithIV;
176 | }
177 | catch(InvalidCipherTextException e) {
178 | Log.e(TAG, "Can't encrypt data", e);
179 | }
180 | return null;
181 | }
182 |
183 | protected byte[] decrypt(byte[] data) {
184 |
185 | try {
186 | SecretKey key = loadKey();
187 |
188 | byte[] ivBytes = new byte[16]; // 16 bytes is the IV size for AES256
189 | System.arraycopy(data, 0, ivBytes, 0, ivBytes.length); // Get IV from data
190 | byte[] dataWithoutIV = new byte[data.length - ivBytes.length]; // Remove the room made for the IV
191 | System.arraycopy(data, ivBytes.length, dataWithoutIV, 0, dataWithoutIV.length); // Then the encrypted data
192 |
193 | PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESFastEngine()));
194 | cipher.init(false, new ParametersWithIV(new KeyParameter(key.getEncoded()), ivBytes));
195 |
196 | return cipherData(cipher, dataWithoutIV);
197 | }
198 | catch(InvalidCipherTextException e) {
199 | Log.e(TAG, "Can't decrypt data", e);
200 | }
201 | return null;
202 | }
203 |
204 | //endregion
205 |
206 | }
207 |
--------------------------------------------------------------------------------
/oidclib/src/main/java/com/lnikkila/oidc/security/SensitiveDataUtils.java:
--------------------------------------------------------------------------------
1 | package com.lnikkila.oidc.security;
2 |
3 | import android.content.Context;
4 | import android.support.annotation.NonNull;
5 | import android.text.TextUtils;
6 | import android.util.Base64;
7 | import android.util.Log;
8 |
9 | import java.io.UnsupportedEncodingException;
10 | import java.lang.ref.WeakReference;
11 |
12 | import javax.crypto.SecretKey;
13 |
14 | /**
15 | * Created by Camilo Montes on 18/01/2016.
16 | * @see http://lukieb.blogspot.fr/2013/11/aes-encryptiondecryption-in-android.html
17 | */
18 | public abstract class SensitiveDataUtils {
19 |
20 | //region Constants
21 |
22 | protected static final String TAG = "SensitiveDataStorage";
23 |
24 | protected static final String CIPHER_ALGO = "AES";
25 | protected static final int CIPHER_KEY_LENGHT = 256;
26 |
27 | protected static final String IO_ENCODING = "UTF-8";
28 |
29 | //endregion
30 |
31 | protected final WeakReference context;
32 |
33 | public SensitiveDataUtils(Context context) {
34 | this.context = new WeakReference<>(context);
35 | createAndSaveSecretKey();
36 | }
37 |
38 | /**
39 | * Creates and saves a new secret key
40 | */
41 | protected abstract void createAndSaveSecretKey();
42 |
43 | /**
44 | * Generate a key suitable for {@link #CIPHER_ALGO} encryption and {@link #CIPHER_KEY_LENGHT} key length.
45 | *
46 | * Usually {@link #CIPHER_ALGO} = "AES" and {@link #CIPHER_KEY_LENGHT} = 256
47 | * @return The generated key
48 | */
49 | protected abstract SecretKey generateKey();
50 |
51 | /**
52 | * Encrypt the given plaintext bytes using the given key
53 | * @param data The plaintext to encrypt
54 | * @return The encrypted bytes
55 | */
56 | protected abstract byte[] encrypt(byte[] data) throws UserNotAuthenticatedWrapperException;
57 |
58 | /**
59 | * Encrypt the given plaintext using the priviously created key.
60 | * @param data The plaintext to encrypt
61 | * @return The encrypted string
62 | */
63 | public String encrypt(@NonNull String data) throws UserNotAuthenticatedWrapperException {
64 | String encryptedString = null;
65 | if (!TextUtils.isEmpty(data)) {
66 | try {
67 | byte[] encrypted = encrypt(data.getBytes(IO_ENCODING));
68 | encryptedString = Base64.encodeToString(encrypted, Base64.DEFAULT);
69 | } catch (UnsupportedEncodingException e) {
70 | Log.e(TAG, String.format("The given data coud not be decoded using %1$s encoding", IO_ENCODING), e);
71 | }
72 | } else {
73 | Log.e(TAG, "Can not encrypt empty data");
74 | }
75 | return encryptedString;
76 | }
77 |
78 | /**
79 | * Decrypt the given data with the given key
80 | * @param data The data to decrypt
81 | * @return The decrypted bytes
82 | */
83 | protected abstract byte[] decrypt(byte[] data) throws UserNotAuthenticatedWrapperException;
84 |
85 | /**
86 | * Decrypt the given data using the priviously created key.
87 | * @param encryptedData The data to decrypt
88 | * @return The decrypted string
89 | */
90 | public String decrypt(@NonNull String encryptedData) throws UserNotAuthenticatedWrapperException {
91 | String data = null;
92 | if (!TextUtils.isEmpty(encryptedData)) {
93 | try {
94 | byte[] decrypted = decrypt(Base64.decode(encryptedData, Base64.DEFAULT));
95 | data = new String(decrypted, IO_ENCODING);
96 | } catch (UnsupportedEncodingException e) {
97 | Log.e(TAG, String.format("The given data coud not be decoded using %1$s encoding", IO_ENCODING), e);
98 | }
99 | } else {
100 | Log.e(TAG, "Can not decrypt empty data");
101 | }
102 | return data;
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/oidclib/src/main/java/com/lnikkila/oidc/security/UserNotAuthenticatedWrapperException.java:
--------------------------------------------------------------------------------
1 | package com.lnikkila.oidc.security;
2 |
3 | /**
4 | * Wrapper for {@link android.security.keystore.UserNotAuthenticatedException} because it does not
5 | * exist in pre M APIs.
6 | * Created by Camilo Montes on 20/01/2016.
7 | */
8 | public class UserNotAuthenticatedWrapperException extends Exception {
9 |
10 | public UserNotAuthenticatedWrapperException(Throwable throwable) {
11 | super(throwable);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/oidclib/src/main/res/color/oidc_button_color_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/oidclib/src/main/res/color/primary_text_inv_sel.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/oidclib/src/main/res/color/primary_text_sel.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/oidclib/src/main/res/color/secondary_text_inv_sel.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/oidclib/src/main/res/color/secondary_text_sel.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/oidclib/src/main/res/drawable-mdpi/ic_account_authenticator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoftgraph/android-java-connect-rest-sample/ba07bf5b7304c1e18eccdb5c008450605b696ac7/oidclib/src/main/res/drawable-mdpi/ic_account_authenticator.png
--------------------------------------------------------------------------------
/oidclib/src/main/res/drawable-mdpi/ic_small_account_authenticator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoftgraph/android-java-connect-rest-sample/ba07bf5b7304c1e18eccdb5c008450605b696ac7/oidclib/src/main/res/drawable-mdpi/ic_small_account_authenticator.png
--------------------------------------------------------------------------------
/oidclib/src/main/res/drawable-xhdpi/ic_account_authenticator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoftgraph/android-java-connect-rest-sample/ba07bf5b7304c1e18eccdb5c008450605b696ac7/oidclib/src/main/res/drawable-xhdpi/ic_account_authenticator.png
--------------------------------------------------------------------------------
/oidclib/src/main/res/drawable-xhdpi/ic_small_account_authenticator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoftgraph/android-java-connect-rest-sample/ba07bf5b7304c1e18eccdb5c008450605b696ac7/oidclib/src/main/res/drawable-xhdpi/ic_small_account_authenticator.png
--------------------------------------------------------------------------------
/oidclib/src/main/res/drawable-xxhdpi/ic_account_authenticator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoftgraph/android-java-connect-rest-sample/ba07bf5b7304c1e18eccdb5c008450605b696ac7/oidclib/src/main/res/drawable-xxhdpi/ic_account_authenticator.png
--------------------------------------------------------------------------------
/oidclib/src/main/res/drawable-xxhdpi/ic_small_account_authenticator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoftgraph/android-java-connect-rest-sample/ba07bf5b7304c1e18eccdb5c008450605b696ac7/oidclib/src/main/res/drawable-xxhdpi/ic_small_account_authenticator.png
--------------------------------------------------------------------------------
/oidclib/src/main/res/drawable/ic_account_authenticator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoftgraph/android-java-connect-rest-sample/ba07bf5b7304c1e18eccdb5c008450605b696ac7/oidclib/src/main/res/drawable/ic_account_authenticator.png
--------------------------------------------------------------------------------
/oidclib/src/main/res/drawable/ic_small_account_authenticator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoftgraph/android-java-connect-rest-sample/ba07bf5b7304c1e18eccdb5c008450605b696ac7/oidclib/src/main/res/drawable/ic_small_account_authenticator.png
--------------------------------------------------------------------------------
/oidclib/src/main/res/layout/activity_authentication.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
23 |
27 |
28 |
33 |
41 |
42 |
43 |
48 |
56 |
57 |
58 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/oidclib/src/main/res/layout/activity_clientconfiguration.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
17 |
22 |
23 |
29 |
30 |
35 |
43 |
44 |
45 |
50 |
58 |
59 |
60 |
65 |
73 |
74 |
75 |
80 |
88 |
89 |
90 |
95 |
103 |
104 |
105 |
113 |
114 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/oidclib/src/main/res/layout/spinner_dropdown_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
--------------------------------------------------------------------------------
/oidclib/src/main/res/layout/spinner_selected_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/oidclib/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFC107
4 | #FFA000
5 | #FF6F00
6 | #fafafa
7 | #000000
8 | #000000
9 | #de000000
10 | #ffffff
11 | #9e9c9c
12 | #8a000000
13 | #8a000000
14 | #b3ffffff
15 | #b3ffffff
16 | #FFFFFF
17 | #a8a8a8
18 |
--------------------------------------------------------------------------------
/oidclib/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | - 0.26
4 | - 0.30
5 | - 0.30
6 | - 0.30
7 |
8 |
--------------------------------------------------------------------------------
/oidclib/src/main/res/values/identifiers.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | com.lnikkila.oidclib.account
9 |
10 |
11 | OIDC Android Client
12 |
13 |
14 |
--------------------------------------------------------------------------------
/oidclib/src/main/res/values/oidc_clientconf.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
10 | true
11 |
12 |
13 | 7de59867-868d-44c3-ad29-c035bc3a680d
14 |
15 |
16 |
19 | https://login.microsoftonline.com/common/oauth2/nativeclient
20 |
21 |
25 |
26 | - openid
27 | - profile
28 | - User.Read
29 | - Mail.Send
30 | - https://graph.microsoft.com/User.ReadBasic.All
31 | - offline_access
32 |
33 |
34 |
38 | Code
39 |
40 |
43 | https://example.com
44 |
--------------------------------------------------------------------------------
/oidclib/src/main/res/values/oidc_clientoptions.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
11 | - prompt|login
12 |
14 | - access_type|offline
15 |
16 |
17 |
19 | oidcEncryptionKey
20 |
21 |
24 | false
25 |
26 |
29 | 0
30 |
31 |
33 | true
34 |
--------------------------------------------------------------------------------
/oidclib/src/main/res/values/oidc_endpoints.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | example
5 | https://login.microsoftonline.com/common/oauth2/v2.0/authorize
6 | https://login.microsoftonline.com/common/oauth2/v2.0/token
7 | https://graph.microsoft.com/v1.0/me
8 | https://www.example.com/oauth2/revoketoken
9 |
--------------------------------------------------------------------------------
/oidclib/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | OIDC Android Client
3 |
4 | Use OAuth2 only
5 | Client Id
6 | Client Password
7 | Redirect URL
8 | Issuer
9 | Scopes (separed by space)
10 | Flow Type %1$s
11 | SAVE CHANCES
12 |
13 | Username
14 | Password
15 | LOG IN
16 |
17 | Mandatory
18 |
19 |
--------------------------------------------------------------------------------
/oidclib/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
22 |
23 |
34 |
35 |
47 |
48 |
54 |
55 |
58 |
59 |
63 |
64 |
--------------------------------------------------------------------------------
/oidclib/src/main/res/values/theme.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
22 |
--------------------------------------------------------------------------------
/oidclib/src/main/res/xml/authenticator.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/readme-images/O365-Android-Connect-Constants.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoftgraph/android-java-connect-rest-sample/ba07bf5b7304c1e18eccdb5c008450605b696ac7/readme-images/O365-Android-Connect-Constants.png
--------------------------------------------------------------------------------
/readme-images/O365-Android-Connect-video_play_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoftgraph/android-java-connect-rest-sample/ba07bf5b7304c1e18eccdb5c008450605b696ac7/readme-images/O365-Android-Connect-video_play_icon.png
--------------------------------------------------------------------------------
/readme-images/o365-android-microsoft-graph-permissions.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoftgraph/android-java-connect-rest-sample/ba07bf5b7304c1e18eccdb5c008450605b696ac7/readme-images/o365-android-microsoft-graph-permissions.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 | include ':oidclib'
--------------------------------------------------------------------------------