I'm trying to hook my Android application up to Google Calendars. I've followed the quick start tutorial, have asked the user for permission to write to external storage, yet I cannot get the code to run without throwing a java.io.IOException.
My code looks like this:
GoogleCalendarModule.kt
class GoogleCalendarModule {
var APPLICATION_NAME: String = "Conglobo"
var JSON_FACTORY: JacksonFactory = JacksonFactory.getDefaultInstance()
var TOKENS_DIRECTORY_PATH: String = "./tokens"
var SCOPES: List<String> = Collections.singletonList(CalendarScopes.CALENDAR_READONLY)
private var CREDENTIALS_FILE_PATH: String = "/credentials.json"
fun getCredentials(HTTP_TRANSPORT: NetHttpTransport): com.google.api.client.auth.oauth2.Credential? {
val inputStream: InputStream = this.javaClass.getResourceAsStream(CREDENTIALS_FILE_PATH)
?: throw FileNotFoundException("Resource Not found: $CREDENTIALS_FILE_PATH")
val clientSecrets: GoogleClientSecrets = GoogleClientSecrets.load(JSON_FACTORY, InputStreamReader(inputStream))
val tokenFolder = File(getExternalStorageDirectory(), File.separator.toString() + TOKENS_DIRECTORY_PATH)
if (!tokenFolder.exists()) {
tokenFolder.mkdirs()
}
val flow: GoogleAuthorizationCodeFlow = GoogleAuthorizationCodeFlow.Builder(
HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
.setDataStoreFactory(FileDataStoreFactory(tokenFolder))
.setAccessType("offline")
.build();
val receiver: LocalServerReceiver = LocalServerReceiver.Builder().setPort(8888).build()
return AuthorizationCodeInstalledApp(flow, receiver).authorize("user")
}
fun doSomething() {
val HTTP_TRANSPORT = NetHttpTransport()
val service: Calendar = Calendar.Builder(HTTP_TRANSPORT, JSON_FACTORY, getCredentials(HTTP_TRANSPORT))
.setApplicationName(APPLICATION_NAME)
.build()
val now = DateTime(System.currentTimeMillis())
val events: Events = service.events().list("primary")
.setMaxResults(10)
.setTimeMin(now)
.setOrderBy("startTime")
.setSingleEvents(true)
.execute()
val items: List<Event> = events.items
if (items.isEmpty()) {
println("No events")
} else {
println("Upcoming events")
for(event: Event in items) {
var start: DateTime = event.start.dateTime
if(start == null) {
start = event.start.date
}
print(event.summary)
}
}
}
}
Then I check against current permissions in the MainActivity
MainActivity.kt
class MainActivity: AppCompatActivity(), ITeamFragmentDelegate {
@Inject
lateinit var teamInfoModule: TeamInfoModule;
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {
print("Permission is granted");
} else {
print("Permission is revoked");
ActivityCompat.requestPermissions(this, Array<String>(1) { Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
}
}
GoogleCalendarModule().doSomething()
setContentView(R.layout.activity_main)
DaggerServiceModuleComponent.create().inject(this)
val teamArrayList: ArrayList<Team> = this.teamInfoModule.getAllTeamData()
for(team: Team in teamArrayList) {
val bundle = Bundle()
val teamFragment = TeamFragment()
bundle.putParcelable("teamData", team)
teamFragment.arguments = bundle
supportFragmentManager.beginTransaction()
.add(R.id.root_container, teamFragment)
.commitAllowingStateLoss()
}
}
override fun onTeamClicked(fragment: TeamFragment, team: Team) {
val intent = Intent(this, ViewTeamBacklogActivity::class.java)
intent.putExtra("teamId", team.id)
startActivity(intent)
}
}
And I even have the permissions declared in AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.bluelightlite">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".ViewTeamBacklogActivity">
</activity>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
I've searched around S.O and it appears to be a common problem but none of the solutions I've found have worked. Could someone please help?