Add some permission infrastructure, add an ugly button that asks you to grant STORAGE permission if necessary.

This commit is contained in:
Henrik Rydgard 2015-12-17 22:41:50 +01:00
parent 2d22088f38
commit 732b1239e7
14 changed files with 151 additions and 56 deletions

View file

@ -722,48 +722,52 @@ void MainScreen::CreateViews() {
tabRecentGames->OnHoldChoice.Handle(this, &MainScreen::OnGameSelected);
tabRecentGames->OnHighlight.Handle(this, &MainScreen::OnGameHighlight);
}
ScrollView *scrollAllGames = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
ScrollView *scrollHomebrew = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
GameBrowser *tabAllGames = new GameBrowser(g_Config.currentDirectory, true, &g_Config.bGridView2,
mm->T("How to get games"), "http://www.ppsspp.org/getgames.html", 0,
new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
GameBrowser *tabHomebrew = new GameBrowser(GetSysDirectory(DIRECTORY_GAME), false, &g_Config.bGridView3,
mm->T("How to get homebrew & demos", "How to get homebrew && demos"), "http://www.ppsspp.org/gethomebrew.html",
FLAG_HOMEBREWSTOREBUTTON,
new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
if (System_GetPermissionStatus(SYSTEM_PERMISSION_STORAGE) == PERMISSION_STATUS_GRANTED) {
ScrollView *scrollAllGames = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
ScrollView *scrollHomebrew = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
Choice *hbStore = tabHomebrew->HomebrewStoreButton();
if (hbStore) {
hbStore->OnClick.Handle(this, &MainScreen::OnHomebrewStore);
}
GameBrowser *tabAllGames = new GameBrowser(g_Config.currentDirectory, true, &g_Config.bGridView2,
mm->T("How to get games"), "http://www.ppsspp.org/getgames.html", 0,
new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
GameBrowser *tabHomebrew = new GameBrowser(GetSysDirectory(DIRECTORY_GAME), false, &g_Config.bGridView3,
mm->T("How to get homebrew & demos", "How to get homebrew && demos"), "http://www.ppsspp.org/gethomebrew.html",
FLAG_HOMEBREWSTOREBUTTON,
new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
scrollAllGames->Add(tabAllGames);
scrollHomebrew->Add(tabHomebrew);
Choice *hbStore = tabHomebrew->HomebrewStoreButton();
if (hbStore) {
hbStore->OnClick.Handle(this, &MainScreen::OnHomebrewStore);
}
leftColumn->AddTab(mm->T("Games"), scrollAllGames);
leftColumn->AddTab(mm->T("Homebrew & Demos"), scrollHomebrew);
scrollAllGames->Add(tabAllGames);
scrollHomebrew->Add(tabHomebrew);
tabAllGames->OnChoice.Handle(this, &MainScreen::OnGameSelectedInstant);
tabHomebrew->OnChoice.Handle(this, &MainScreen::OnGameSelectedInstant);
leftColumn->AddTab(mm->T("Games"), scrollAllGames);
leftColumn->AddTab(mm->T("Homebrew & Demos"), scrollHomebrew);
tabAllGames->OnHoldChoice.Handle(this, &MainScreen::OnGameSelected);
tabHomebrew->OnHoldChoice.Handle(this, &MainScreen::OnGameSelected);
tabAllGames->OnChoice.Handle(this, &MainScreen::OnGameSelectedInstant);
tabHomebrew->OnChoice.Handle(this, &MainScreen::OnGameSelectedInstant);
tabAllGames->OnHighlight.Handle(this, &MainScreen::OnGameHighlight);
tabHomebrew->OnHighlight.Handle(this, &MainScreen::OnGameHighlight);
tabAllGames->OnHoldChoice.Handle(this, &MainScreen::OnGameSelected);
tabHomebrew->OnHoldChoice.Handle(this, &MainScreen::OnGameSelected);
if (g_Config.recentIsos.size() > 0) {
leftColumn->SetCurrentTab(0);
} else if (g_Config.iMaxRecent > 0) {
leftColumn->SetCurrentTab(1);
}
tabAllGames->OnHighlight.Handle(this, &MainScreen::OnGameHighlight);
tabHomebrew->OnHighlight.Handle(this, &MainScreen::OnGameHighlight);
if (backFromStore_ || showHomebrewTab) {
leftColumn->SetCurrentTab(2);
backFromStore_ = false;
showHomebrewTab = false;
if (g_Config.recentIsos.size() > 0) {
leftColumn->SetCurrentTab(0);
} else if (g_Config.iMaxRecent > 0) {
leftColumn->SetCurrentTab(1);
}
if (backFromStore_ || showHomebrewTab) {
leftColumn->SetCurrentTab(2);
backFromStore_ = false;
showHomebrewTab = false;
}
} else {
leftColumn->Add(new Button(mm->T("Give PPSSPP permission to access storage")))->OnClick.Handle(this, &MainScreen::OnAllowStorage);
}
/* if (info) {
@ -845,6 +849,11 @@ void MainScreen::CreateViews() {
}
}
UI::EventReturn MainScreen::OnAllowStorage(UI::EventParams &e) {
System_AskForPermission(SYSTEM_PERMISSION_STORAGE);
return UI::EVENT_DONE;
}
UI::EventReturn MainScreen::OnDownloadUpgrade(UI::EventParams &e) {
#ifdef ANDROID
// Go to app store
@ -882,6 +891,9 @@ void MainScreen::sendMessage(const char *message, const char *value) {
UpdateUIState(UISTATE_MENU);
screenManager()->push(new GameSettingsScreen(""));
}
if (!strcmp(message, "permission_granted") && !strcmp(value, "storage")) {
RecreateViews();
}
}
void MainScreen::update(InputState &input) {

View file

@ -93,6 +93,7 @@ private:
UI::EventReturn OnDownloadUpgrade(UI::EventParams &e);
UI::EventReturn OnDismissUpgrade(UI::EventParams &e);
UI::EventReturn OnHomebrewStore(UI::EventParams &e);
UI::EventReturn OnAllowStorage(UI::EventParams &e);
UI::LinearLayout *upgradeBar_;
UI::TabHolder *tabHolder_;

View file

@ -974,3 +974,7 @@ void NativeShutdown() {
RemoveFontResourceEx(L"assets/Roboto-Condensed.ttf", FR_PRIVATE, NULL);
#endif
}
void NativePermissionStatus(SystemPermission permission, PermissionStatus status) {
// TODO: Send this through the screen system? Nicer than listening to string messages
}

View file

@ -289,6 +289,9 @@ void System_SendMessage(const char *command, const char *parameter) {
}
}
void System_AskForPermission(SystemPermission permission) {}
PermissionStatus System_GetPermissionStatus(SystemPermission permission) { return PERMISSION_STATUS_GRANTED; }
void EnableCrashingOnCrashes() {
typedef BOOL (WINAPI *tGetPolicy)(LPDWORD lpFlags);
typedef BOOL (WINAPI *tSetPolicy)(DWORD dwFlags);

View file

@ -86,44 +86,42 @@ InputState input_state;
static bool renderer_inited = false;
static bool first_lost = true;
static std::string library_path;
static std::map<SystemPermission, PermissionStatus> permissions;
void PushCommand(std::string cmd, std::string param) {
lock_guard guard(frameCommandLock);
frameCommands.push(FrameCommand(cmd, param));
}
// Android implementation of callbacks to the Java part of the app
void SystemToast(const char *text) {
lock_guard guard(frameCommandLock);
frameCommands.push(FrameCommand("toast", text));
PushCommand("toast", text);
}
void ShowKeyboard() {
lock_guard guard(frameCommandLock);
frameCommands.push(FrameCommand("showKeyboard", ""));
PushCommand("showKeyboard", "");
}
void Vibrate(int length_ms) {
lock_guard guard(frameCommandLock);
char temp[32];
sprintf(temp, "%i", length_ms);
frameCommands.push(FrameCommand("vibrate", temp));
PushCommand("vibrate", temp);
}
void LaunchBrowser(const char *url) {
lock_guard guard(frameCommandLock);
frameCommands.push(FrameCommand("launchBrowser", url));
PushCommand("launchBrowser", url);
}
void LaunchMarket(const char *url) {
lock_guard guard(frameCommandLock);
frameCommands.push(FrameCommand("launchMarket", url));
PushCommand("launchMarket", url);
}
void LaunchEmail(const char *email_address) {
lock_guard guard(frameCommandLock);
frameCommands.push(FrameCommand("launchEmail", email_address));
PushCommand("launchEmail", email_address);
}
void System_SendMessage(const char *command, const char *parameter) {
lock_guard guard(frameCommandLock);
frameCommands.push(FrameCommand(command, parameter));
PushCommand(command, parameter);
}
std::string System_GetProperty(SystemProperty prop) {
@ -159,6 +157,8 @@ int System_GetPropertyInt(SystemProperty prop) {
return optimalFramesPerBuffer;
case SYSPROP_DISPLAY_REFRESH_RATE:
return (int)(display_hz * 1000.0);
case SYSPROP_SUPPORTS_PERMISSIONS:
return androidVersion >= 23; // 6.0 Marshmallow introduced run time permissions.
default:
return -1;
}
@ -327,6 +327,22 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayShutdown(JNIEnv *en
}
}
void System_AskForPermission(SystemPermission permission) {
switch (permission) {
case SYSTEM_PERMISSION_STORAGE:
PushCommand("ask_permission", "storage");
break;
}
}
PermissionStatus System_GetPermissionStatus(SystemPermission permission) {
if (androidVersion < 23) {
return PERMISSION_STATUS_GRANTED;
} else {
return permissions[permission];
}
}
extern "C" jboolean JNICALL Java_org_ppsspp_ppsspp_NativeApp_touch
(JNIEnv *, jclass, float x, float y, int code, int pointerId) {
float scaledX = x * dp_xscale;
@ -460,9 +476,21 @@ extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_sendMessage(JNIEnv *env
std::string msg = GetJavaString(env, message);
std::string prm = GetJavaString(env, param);
// Some messages are caught by app-android.
if (msg == "moga") {
mogaVersion = prm;
} else if (msg == "permission_pending") {
// TODO: Add support for other permissions
permissions[SYSTEM_PERMISSION_STORAGE] = PERMISSION_STATUS_PENDING;
NativePermissionStatus(SYSTEM_PERMISSION_STORAGE, PERMISSION_STATUS_PENDING);
} else if (msg == "permission_denied") {
permissions[SYSTEM_PERMISSION_STORAGE] = PERMISSION_STATUS_DENIED;
NativePermissionStatus(SYSTEM_PERMISSION_STORAGE, PERMISSION_STATUS_PENDING);
} else if (msg == "permission_granted") {
permissions[SYSTEM_PERMISSION_STORAGE] = PERMISSION_STATUS_GRANTED;
NativePermissionStatus(SYSTEM_PERMISSION_STORAGE, PERMISSION_STATUS_PENDING);
}
NativeMessageReceived(msg.c_str(), prm.c_str());
}

View file

@ -197,10 +197,7 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback {
detectOptimalAudioSettings();
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
askForStoragePermission();
}
// Get system information
// Get system information
ApplicationInfo appInfo = null;
PackageManager packMgmr = getPackageManager();
String packageName = getPackageName();
@ -742,10 +739,22 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback {
@TargetApi(11)
@SuppressWarnings("deprecation")
private AlertDialog.Builder createDialogBuilderWithTheme() {
return new AlertDialog.Builder(this, AlertDialog.THEME_HOLO_DARK);
}
@TargetApi(14)
@SuppressWarnings("deprecation")
private AlertDialog.Builder createDialogBuilderWithDeviceTheme() {
return new AlertDialog.Builder(this, AlertDialog.THEME_DEVICE_DEFAULT_DARK);
}
@TargetApi(23)
private AlertDialog.Builder createDialogBuilderNew() {
return new AlertDialog.Builder(this, android.R.style.Theme_DeviceDefault_Dialog_Alert);
}
// The return value is sent elsewhere. TODO in java, in SendMessage in C++.
public void inputBox(String title, String defaultText, String defaultAction) {
final FrameLayout fl = new FrameLayout(this);
@ -760,11 +769,16 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback {
input.setText(defaultText);
input.selectAll();
// Lovely!
AlertDialog.Builder bld = null;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB)
bld = new AlertDialog.Builder(this);
else
else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH)
bld = createDialogBuilderWithTheme();
else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
bld = createDialogBuilderWithDeviceTheme();
else
bld = createDialogBuilderNew();
AlertDialog dlg = bld
.setView(fl)
@ -935,8 +949,8 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback {
} else if (command.equals("recreate")) {
exitEGLRenderLoop();
recreate();
} else if (command.equals("ask_permission")) {
} else if (command.equals("ask_permission") && params.equals("storage")) {
askForStoragePermission();
}
return false;
}

View file

@ -7,7 +7,6 @@ package org.ppsspp.ppsspp;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.graphics.PixelFormat;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;

View file

@ -63,6 +63,9 @@ void System_SendMessage(const char *command, const char *parameter) {
}
}
void System_AskForPermission(SystemPermission permission) {}
PermissionStatus System_GetPermissionStatus(SystemPermission permission) { return PERMISSION_STATUS_GRANTED; }
void SystemToast(const char *text) {
dialog_instance_t dialog = 0;
dialog_create_toast(&dialog);

View file

@ -14,6 +14,17 @@ struct TouchInput;
struct KeyInput;
struct AxisInput;
enum SystemPermission {
SYSTEM_PERMISSION_STORAGE,
};
enum PermissionStatus {
PERMISSION_STATUS_UNKNOWN,
PERMISSION_STATUS_DENIED,
PERMISSION_STATUS_PENDING,
PERMISSION_STATUS_GRANTED,
};
// The first function to get called, just write strings to the two pointers.
// This might get called multiple times in some implementations, you must be able to handle that.
void NativeGetAppInfo(std::string *app_dir_name, std::string *app_nice_name, bool *landscape, std::string *version);
@ -94,6 +105,8 @@ void NativeShutdown();
void NativeRestoreState(bool firstTime); // onCreate
void NativeSaveState(); // onDestroy
void NativePermissionStatus(SystemPermission permission, PermissionStatus status);
// Calls back into Java / SDL
// These APIs must be implemented by every port (for example app-android.cpp, PCMain.cpp).
// You are free to call these.
@ -118,6 +131,8 @@ void LaunchEmail(const char *email_address);
bool System_InputBoxGetString(const char *title, const char *defaultValue, char *outValue, size_t outlength);
bool System_InputBoxGetWString(const wchar_t *title, const std::wstring &defaultValue, std::wstring &outValue);
void System_SendMessage(const char *command, const char *parameter);
PermissionStatus System_GetPermissionStatus(SystemPermission permission);
void System_AskForPermission(SystemPermission permission);
// This will get muddy with multi-screen support :/ But this will always be the type of the main device.
enum SystemDeviceType {
@ -149,6 +164,8 @@ enum SystemProperty {
SYSPROP_AUDIO_FRAMES_PER_BUFFER,
SYSPROP_AUDIO_OPTIMAL_SAMPLE_RATE,
SYSPROP_AUDIO_OPTIMAL_FRAMES_PER_BUFFER,
SYSPROP_SUPPORTS_PERMISSIONS,
};
std::string System_GetProperty(SystemProperty prop);

View file

@ -245,6 +245,9 @@ void System_SendMessage(const char *command, const char *parameter) {
}
}
void System_AskForPermission(SystemPermission permission) {}
PermissionStatus System_GetPermissionStatus(SystemPermission permission) { return PERMISSION_STATUS_GRANTED; }
void LaunchBrowser(const char *url) {
#if defined(MOBILE_DEVICE)
ILOG("Would have gone to %s but LaunchBrowser is not implemented on this platform", url);

View file

@ -104,6 +104,9 @@ void System_SendMessage(const char *command, const char *parameter) {
}
}
void System_AskForPermission(SystemPermission permission) {}
PermissionStatus System_GetPermissionStatus(SystemPermission permission) { return PERMISSION_STATUS_GRANTED; }
bool System_InputBoxGetString(const char *title, const char *defaultValue, char *outValue, size_t outLength)
{
QString text = emugl->InputBoxGetQString(QString(title), QString(defaultValue));

View file

@ -80,6 +80,8 @@ std::string System_GetProperty(SystemProperty prop) { return ""; }
int System_GetPropertyInt(SystemProperty prop) { return -1; }
void System_SendMessage(const char *command, const char *parameter) {}
bool System_InputBoxGetWString(const wchar_t *title, const std::wstring &defaultvalue, std::wstring &outvalue) { return false; }
void System_AskForPermission(SystemPermission permission) {}
PermissionStatus System_GetPermissionStatus(SystemPermission permission) { return PERMISSION_STATUS_GRANTED; }
#ifndef _WIN32
InputState input_state;

View file

@ -74,6 +74,9 @@ void System_SendMessage(const char *command, const char *parameter) {
}
}
void System_AskForPermission(SystemPermission permission) {}
PermissionStatus System_GetPermissionStatus(SystemPermission permission) { return PERMISSION_STATUS_GRANTED; }
FOUNDATION_EXTERN void AudioServicesPlaySystemSoundWithVibration(unsigned long, objc_object*, NSDictionary*);
void Vibrate(int length_ms) {

View file

@ -18,6 +18,7 @@
#include <algorithm>
#include "base/timeutil.h"
#include "base/NativeApp.h"
#include "input/input_state.h"
#include "Core/MIPS/JitCommon/JitCommon.h"
#include "Core/MIPS/JitCommon/NativeJit.h"
@ -40,6 +41,8 @@ void NativeResized() { }
void System_SendMessage(const char *command, const char *parameter) {}
bool System_InputBoxGetWString(const wchar_t *title, const std::wstring &defaultvalue, std::wstring &outvalue) { return false; }
void System_AskForPermission(SystemPermission permission) {}
PermissionStatus System_GetPermissionStatus(SystemPermission permission) { return PERMISSION_STATUS_GRANTED; }
#ifndef _WIN32
InputState input_state;
@ -198,4 +201,4 @@ bool TestJit() {
DestroyJitHarness();
return jit_speed >= interp_speed;
}
}