mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 07:49:44 +08:00
Fixed ILayoutInflater not inflating any views
This commit is contained in:
@@ -1,8 +1,6 @@
|
||||
/************************************************************************************
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
@@ -17,8 +15,6 @@
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**************************************************************************************/
|
||||
|
||||
|
||||
package com.itsaky.androidide;
|
||||
|
||||
import android.content.Context;
|
||||
@@ -68,6 +64,8 @@ public class DesignerActivity extends StudioActivity {
|
||||
} catch (Throwable th) {
|
||||
mBinding.realContainer.removeAllViews();
|
||||
mBinding.realContainer.addView(createErrorText(th));
|
||||
|
||||
LOG.error (getString(R.string.err_cannot_inflate_layout));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,92 +86,4 @@ public class DesignerActivity extends StudioActivity {
|
||||
error.setBackgroundColor(ContextCompat.getColor(this, android.R.color.white));
|
||||
return error;
|
||||
}
|
||||
|
||||
private String printRClassHierarchy () throws IllegalArgumentException, IllegalAccessException {
|
||||
return printClassHierarchy(android.R.class, 0);
|
||||
}
|
||||
|
||||
private String printClassHierarchy (Class<?> clazz, int indent) throws IllegalArgumentException, IllegalAccessException {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("class " + clazz.getName() + " {");
|
||||
newLineIndent(sb, ++indent);
|
||||
|
||||
sb.append("fields : [");
|
||||
newLineIndent(sb, ++indent);
|
||||
printFields (sb, clazz, indent);
|
||||
newLineIndent(sb, --indent);
|
||||
sb.append("]");
|
||||
|
||||
newLineIndent(sb, indent);
|
||||
sb.append("classes : [");
|
||||
newLineIndent(sb, ++indent);
|
||||
printClasses (sb, clazz, indent);
|
||||
newLineIndent(sb, --indent);
|
||||
sb.append("]");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void newLineIndent(StringBuilder sb, int indent) {
|
||||
sb.append("\n");
|
||||
sb.append(repeat(" ", indent * 4));
|
||||
}
|
||||
|
||||
private void printFields(StringBuilder sb, Class<?> clazz, int indent) throws IllegalArgumentException, IllegalAccessException {
|
||||
boolean first = true;
|
||||
for (Field f : clazz.getDeclaredFields()) {
|
||||
if (!first) {
|
||||
newLineIndent(sb, indent);
|
||||
}
|
||||
if(!f.isAccessible()) {
|
||||
f.setAccessible(true);
|
||||
}
|
||||
sb.append(f.getName());
|
||||
sb.append(" = ");
|
||||
if (f.getType() == int[].class) {
|
||||
printIntArr(sb, (int[]) f.get(null));
|
||||
} else if (f.getType() == int.class) {
|
||||
sb.append(f.get(null));
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void printClasses(StringBuilder sb, Class<?> clazz, int indent) throws IllegalArgumentException, IllegalAccessException {
|
||||
boolean first = true;
|
||||
for (Class<?> c : clazz.getClasses()) {
|
||||
if (!first) {
|
||||
newLineIndent(sb, indent);
|
||||
}
|
||||
sb.append("class " + c.getSimpleName() + " [");
|
||||
newLineIndent(sb, ++indent);
|
||||
printFields(sb, c, indent);
|
||||
newLineIndent(sb, --indent);
|
||||
sb.append("]");
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
private String repeat (String to, int till) {
|
||||
String result = "";
|
||||
for (int i=1;i<=till;i++) {
|
||||
result += to;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void printIntArr (StringBuilder sb, int[] arr) {
|
||||
boolean first = true;
|
||||
sb.append("[");
|
||||
for (int i : arr) {
|
||||
if (!first) {
|
||||
sb.append(", ");
|
||||
}
|
||||
sb.append(i);
|
||||
first = false;
|
||||
}
|
||||
sb.append("]");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ public class DownloadActivity extends StudioActivity {
|
||||
.build()
|
||||
.forResult(abhishekti7.unicorn.filepicker.utils.Constants.REQ_UNICORN_FILE);
|
||||
} catch (Throwable th){
|
||||
LOG.error("Unable to start file picker", th);
|
||||
LOG.error(getString (R.string.err_cannot_start_file_picker), th);
|
||||
}
|
||||
} else if(id == binding.install.getId()) {
|
||||
if(choosenDir == null) {
|
||||
@@ -134,10 +134,10 @@ public class DownloadActivity extends StudioActivity {
|
||||
new Thread (reader).start();
|
||||
|
||||
} catch (DownloadActivity.InstallationException e) {
|
||||
LOG.error("Installation error", e);
|
||||
LOG.error(getString(R.string.err_installation), e);
|
||||
onInstallationFailed(e.exitCode);
|
||||
} catch (IOException e) {
|
||||
LOG.error("Installation error", e);
|
||||
LOG.error(getString(R.string.err_installation), e);
|
||||
onInstallationFailed(5); // Exit code 5 : I/O Error
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,7 +270,7 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
saveAll(false /* No notification */);
|
||||
saved = true;
|
||||
} catch (Throwable th) {
|
||||
LOG.error(":onPause(): Failed to save files", th);
|
||||
LOG.error(getString(R.string.err_cannot_save_files), th);
|
||||
saved = false;
|
||||
}
|
||||
|
||||
@@ -1081,7 +1081,7 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
intent.putExtra(DesignerActivity.KEY_LAYOUT_PATH, mCurrentFile.getAbsolutePath());
|
||||
startActivity(intent);
|
||||
} catch (Throwable th) {
|
||||
LOG.error("Unable to preview layout", th);
|
||||
LOG.error(getString(R.string.err_cannot_preview_layout), th);
|
||||
getApp().toast(R.string.msg_cannot_preview_layout, Toaster.Type.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ public class StudioApp extends BaseApplication {
|
||||
|
||||
mXmlCompletionService = new XMLCompletionService (mAttrInfo, mWidgetInfo);
|
||||
} catch (Throwable th) {
|
||||
LOG.error ("Unable to start XML completion service", th);
|
||||
LOG.error (getString (com.itsaky.androidide.R.string.err_init_sdkinfo), th);
|
||||
}
|
||||
}, "SDK Information Loader").start();
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import org.eclipse.lsp4j.CompletionParams;
|
||||
import org.eclipse.lsp4j.Position;
|
||||
import org.eclipse.lsp4j.TextDocumentIdentifier;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||
import com.itsaky.androidide.app.StudioApp;
|
||||
|
||||
public class JavaAutoComplete implements AutoCompleteProvider {
|
||||
|
||||
@@ -66,10 +67,10 @@ public class JavaAutoComplete implements AutoCompleteProvider {
|
||||
}
|
||||
|
||||
} catch (Throwable th) {
|
||||
LOG.error("CompletionError", th);
|
||||
LOG.error(StudioApp.getInstance().getString(com.itsaky.androidide.R.string.err_completion), th);
|
||||
}
|
||||
} else {
|
||||
LOG.error("Cannot compute completions for Java file. No LanguageServer implementation found.");
|
||||
LOG.error(StudioApp.getInstance().getString(com.itsaky.androidide.R.string.err_no_server_implementation));
|
||||
}
|
||||
return new ArrayList<CompletionItem>();
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/************************************************************************************
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
@@ -17,8 +15,6 @@
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**************************************************************************************/
|
||||
|
||||
|
||||
package com.itsaky.androidide.lsp;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
@@ -80,4 +76,9 @@ public class AsynchronousSocketLauncher extends LSPClientLauncher {
|
||||
|
||||
CloseUtils.closeIOQuietly(serverSocket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLanguageCode() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import org.eclipse.lsp4j.jsonrpc.Launcher;
|
||||
import java.util.Locale;
|
||||
import com.itsaky.androidide.app.StudioApp;
|
||||
|
||||
/**
|
||||
* Launches a client for a Language server and handles connection.
|
||||
@@ -83,7 +84,7 @@ public abstract class LSPClientLauncher extends Thread {
|
||||
try {
|
||||
launch();
|
||||
} catch (Throwable th) {
|
||||
LOG.error("Error starting language server", th);
|
||||
LOG.error(StudioApp.getInstance().getString(com.itsaky.androidide.R.string.err_cannot_start_server, getLanguageCode()), th);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,6 +112,11 @@ public abstract class LSPClientLauncher extends Thread {
|
||||
*/
|
||||
public abstract void shutdown();
|
||||
|
||||
/**
|
||||
* Get the language code for the server
|
||||
*/
|
||||
public abstract String getLanguageCode();
|
||||
|
||||
/**
|
||||
* A listener to listen for language server start event.
|
||||
*/
|
||||
@@ -195,7 +201,7 @@ public abstract class LSPClientLauncher extends Thread {
|
||||
this.out.write(data.data);
|
||||
this.out.flush();
|
||||
} catch (Throwable e) {
|
||||
LOG.error ("Failed to write to LSP4J socket", e);
|
||||
LOG.error (StudioApp.getInstance().getString(com.itsaky.androidide.R.string.err_cannot_write_socket), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.concurrent.Future;
|
||||
import org.eclipse.lsp4j.jsonrpc.Launcher;
|
||||
import com.itsaky.androidide.app.StudioApp;
|
||||
|
||||
public class StandardStreamsLauncher extends LSPClientLauncher {
|
||||
|
||||
@@ -56,8 +57,7 @@ public class StandardStreamsLauncher extends LSPClientLauncher {
|
||||
listening.get();
|
||||
} catch (Throwable th) {
|
||||
LOG.error (
|
||||
"---> StandardStreamsLauncher <---",
|
||||
"An error occured while waiting for language server process to stop",
|
||||
StudioApp.getInstance().getString(com.itsaky.androidide.R.string.err_server_disconnected),
|
||||
th
|
||||
);
|
||||
}
|
||||
@@ -79,4 +79,9 @@ public class StandardStreamsLauncher extends LSPClientLauncher {
|
||||
|
||||
CloseUtils.closeIO(in, out);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLanguageCode() {
|
||||
return this.langCode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ public class JLSHandler implements LSPHandler {
|
||||
mLauncher.start();
|
||||
|
||||
} catch (Throwable th) {
|
||||
LOG.error("Unable to start Java Language server", th);
|
||||
LOG.error(StudioApp.getInstance().getString(com.itsaky.androidide.R.string.err_cannot_start_server, LSPProvider.LANGUAGE_JAVA), th);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ public class JLSHandler implements LSPHandler {
|
||||
final IDELanguageServer server = LSPProvider.getServerForLanguage(LSPProvider.LANGUAGE_JAVA);
|
||||
|
||||
if (server == null) {
|
||||
LOG.error ("Cannot initialize Java Language Server. Server instance is null!");
|
||||
LOG.error (StudioApp.getInstance().getString(com.itsaky.androidide.R.string.err_no_server_implementation));
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ public class JLSHandler implements LSPHandler {
|
||||
}
|
||||
return Optional.of(result);
|
||||
} catch (Throwable e) {
|
||||
LOG.error ("An error occurred while initializing language server.", e);
|
||||
LOG.error (StudioApp.getInstance().getString(com.itsaky.androidide.R.string.err_init_server), e);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/************************************************************************************
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
@@ -17,8 +15,6 @@
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**************************************************************************************/
|
||||
|
||||
|
||||
package com.itsaky.androidide.services.builder;
|
||||
|
||||
import com.itsaky.androidide.project.IDEModule;
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/************************************************************************************
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
*
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
@@ -17,7 +15,6 @@
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**************************************************************************************/
|
||||
|
||||
package com.itsaky.androidide.services.builder;
|
||||
|
||||
import androidx.annotation.StringRes;
|
||||
@@ -151,12 +148,12 @@ public class IDEService {
|
||||
text = line.replace(app.getRootDir().getAbsolutePath(), "HOME");
|
||||
}
|
||||
if (line.contains(app.getRootDir().getParentFile().getAbsolutePath())) {
|
||||
text = line.replace(app.getRootDir().getParentFile().getAbsolutePath(), "ROOT_DIR");
|
||||
text = line.replace(app.getRootDir().getParentFile().getAbsolutePath(), "ROOT");
|
||||
}
|
||||
|
||||
listener.appendOutput(currentTask, text);
|
||||
|
||||
if(line.contains(RUN_TASK)) {
|
||||
if(line.startsWith(RUN_TASK)) {
|
||||
listener.onRunTask(currentTask, line.trim());
|
||||
} else if(line.startsWith(STARTING_DAEMON)) {
|
||||
listener.onStartingGradleDaemon(currentTask);
|
||||
|
||||
+1
-5
@@ -1,8 +1,6 @@
|
||||
/************************************************************************************
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
@@ -17,8 +15,6 @@
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**************************************************************************************/
|
||||
|
||||
|
||||
package com.itsaky.androidide.services.builder;
|
||||
|
||||
import com.blankj.utilcode.util.ThreadUtils;
|
||||
|
||||
@@ -275,4 +275,19 @@
|
||||
<string name="msg_editor_font_size">Please choose default font size of editor :</string>
|
||||
<string name="msg_clear_cache">This will delete caches directory created by Gradle. If you delete it, the next build may take a bit longer than normal as Gradle will download required files again.\nIMPORTANT: This will also delete AAPT2. You will need to reinstall it otherwise you\'ll end up with a build failure.\n\nAre you sure you want to delete caches?</string>
|
||||
|
||||
|
||||
<!-- Error Messages used while Logging -->
|
||||
<string name="err_installation">Installation error</string>
|
||||
<string name="err_completion">Completion error</string>
|
||||
<string name="err_no_server_implementation">No LanguageServer implementation found.</string>
|
||||
<string name="err_init_server">Error initializing language server</string>
|
||||
<string name="err_init_sdkinfo">Unable to initialize SDK Info</string>
|
||||
<string name="err_cannot_start_file_picker">Unable to start file picker</string>
|
||||
<string name="err_cannot_parse_apk_metadata">Failed to parse APK metadata</string>
|
||||
<string name="err_cannot_save_files">Unable to save files</string>
|
||||
<string name="err_cannot_preview_layout">Unable to preview layout</string>
|
||||
<string name="err_cannot_inflate_layout">Unable to inflate layout</string>
|
||||
<string name="err_cannot_start_server">Unable to start Language Server for: %s</string>
|
||||
<string name="err_cannot_write_socket">Failed to write to Socket stream</string>
|
||||
<string name="err_server_disconnected">Language server process unexpectedly exited.</string>
|
||||
</resources>
|
||||
|
||||
@@ -32,5 +32,6 @@ dependencies {
|
||||
implementation 'com.blankj:utilcodex:1.30.6'
|
||||
implementation 'org.jsoup:jsoup:1.14.2'
|
||||
|
||||
implementation project (":common")
|
||||
api project (':sdk-info')
|
||||
}
|
||||
|
||||
+2
-8
@@ -1,8 +1,6 @@
|
||||
/************************************************************************************
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
@@ -27,8 +25,6 @@ import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import com.itsaky.androidide.ui.resources.ResourceTable;
|
||||
import com.itsaky.androidide.ui.resources.ResourceTableFactory;
|
||||
import com.itsaky.androidide.ui.util.Preconditions;
|
||||
import com.itsaky.androidide.ui.view.IAttribute;
|
||||
import com.itsaky.androidide.ui.view.IAttributeAdapter;
|
||||
@@ -65,7 +61,6 @@ class XMLLayoutInflater extends BaseLayoutInflater {
|
||||
private final Set<File> resDirs;
|
||||
private final AttrInfo attrInfo;
|
||||
private final WidgetInfo widgetInfo;
|
||||
private final ResourceTable frameworkResourceTable;
|
||||
private final IResourceFinder resFinder;
|
||||
|
||||
private ContextProvider contextProvider;
|
||||
@@ -94,9 +89,8 @@ class XMLLayoutInflater extends BaseLayoutInflater {
|
||||
this.widgetInfo = config.widgetInfo;
|
||||
this.resFinder = config.resFinder;
|
||||
this.contextProvider = config.contextProvider;
|
||||
this.frameworkResourceTable = ResourceTableFactory.newFrameworkResourceTable();
|
||||
|
||||
Preconditions.assertAllNotNull("LayoutInflater parameters cannot be null", resDirs, attrInfo, widgetInfo, resFinder, frameworkResourceTable);
|
||||
Preconditions.assertAllNotNull("LayoutInflater parameters cannot be null", resDirs, attrInfo, widgetInfo, resFinder);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
-122
@@ -1,122 +0,0 @@
|
||||
/************************************************************************************
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
*
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**************************************************************************************/
|
||||
package com.itsaky.androidide.ui.resources;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class AttributeResource {
|
||||
public static final String ANDROID_NS = "http://schemas.android.com/apk/res/android";
|
||||
public static final String ANDROID_RES_NS_PREFIX = "http://schemas.android.com/apk/res/";
|
||||
public static final String RES_AUTO_NS_URI = "http://schemas.android.com/apk/res-auto";
|
||||
|
||||
public static final String NULL_VALUE = "@null";
|
||||
public static final String EMPTY_VALUE = "@empty";
|
||||
public static final Pattern IS_RESOURCE_REFERENCE = Pattern.compile("^\\s*@");
|
||||
|
||||
public final @NonNull ResName resName;
|
||||
public final @NonNull String value;
|
||||
public final @NonNull String trimmedValue;
|
||||
public final @NonNull String contextPackageName;
|
||||
private final Integer referenceResId;
|
||||
|
||||
public AttributeResource(@NonNull ResName resName, @NonNull String value, @NonNull String contextPackageName) {
|
||||
this(resName, value, contextPackageName, null);
|
||||
}
|
||||
|
||||
public AttributeResource(@NonNull ResName resName, @NonNull String value, @NonNull String contextPackageName, Integer referenceResId) {
|
||||
this.referenceResId = referenceResId;
|
||||
if (!resName.type.equals("attr")) throw new IllegalStateException("\"" + resName.getFullyQualifiedName() + "\" unexpected");
|
||||
|
||||
this.resName = resName;
|
||||
this.value = value;
|
||||
this.trimmedValue = value.trim();
|
||||
this.contextPackageName = contextPackageName;
|
||||
}
|
||||
|
||||
public boolean isResourceReference() {
|
||||
return isResourceReference(trimmedValue);
|
||||
}
|
||||
|
||||
public @NonNull ResName getResourceReference() {
|
||||
if (!isResourceReference()) throw new RuntimeException("not a resource reference: " + this);
|
||||
return ResName.qualifyResName(deref(trimmedValue).replace("+", ""), contextPackageName, "style");
|
||||
}
|
||||
|
||||
public boolean isStyleReference() {
|
||||
return isStyleReference(trimmedValue);
|
||||
}
|
||||
|
||||
public ResName getStyleReference() {
|
||||
if (!isStyleReference()) throw new RuntimeException("not a style reference: " + this);
|
||||
return ResName.qualifyResName(value.substring(1), contextPackageName, "attr");
|
||||
}
|
||||
|
||||
public boolean isNull() {
|
||||
return NULL_VALUE.equals(trimmedValue);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return EMPTY_VALUE.equals(trimmedValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Attribute{" +
|
||||
"name='" + resName + '\'' +
|
||||
", value='" + value + '\'' +
|
||||
", contextPackageName='" + contextPackageName + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
public static boolean isResourceReference(String value) {
|
||||
return IS_RESOURCE_REFERENCE.matcher(value).find() && !isNull(value);
|
||||
}
|
||||
|
||||
public static @NonNull ResName getResourceReference(String value, String defPackage, String defType) {
|
||||
if (!isResourceReference(value)) throw new IllegalArgumentException("not a resource reference: " + value);
|
||||
return ResName.qualifyResName(deref(value).replace("+", ""), defPackage, defType);
|
||||
}
|
||||
|
||||
private static @NonNull String deref(@NonNull String value) {
|
||||
return value.substring(value.indexOf('@') + 1);
|
||||
}
|
||||
|
||||
public static boolean isStyleReference(String value) {
|
||||
return value.startsWith("?");
|
||||
}
|
||||
|
||||
public static ResName getStyleReference(String value, String defPackage, String defType) {
|
||||
if (!isStyleReference(value)) throw new IllegalArgumentException("not a style reference: " + value);
|
||||
return ResName.qualifyResName(value.substring(1), defPackage, defType);
|
||||
}
|
||||
|
||||
public static boolean isNull(String value) {
|
||||
return NULL_VALUE.equals(value);
|
||||
}
|
||||
|
||||
public static boolean isEmpty(String value) {
|
||||
return EMPTY_VALUE.equals(value);
|
||||
}
|
||||
|
||||
public Integer getReferenceResId() {
|
||||
return referenceResId;
|
||||
}
|
||||
}
|
||||
@@ -1,189 +0,0 @@
|
||||
/************************************************************************************
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
*
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**************************************************************************************/
|
||||
package com.itsaky.androidide.ui.resources;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import java.io.File;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class ResName {
|
||||
public static final String ID_TYPE = "id";
|
||||
|
||||
private static final Pattern FQN_PATTERN = Pattern.compile("^([^:]*):([^/]+)/(.+)$");
|
||||
private static final int NAMESPACE = 1;
|
||||
private static final int TYPE = 2;
|
||||
private static final int NAME = 3;
|
||||
|
||||
public final @NonNull String packageName;
|
||||
public final @NonNull String type;
|
||||
public final @NonNull String name;
|
||||
|
||||
public final int hashCode;
|
||||
|
||||
public ResName(@NonNull String packageName, @NonNull String type, @NonNull String name) {
|
||||
this.packageName = packageName;
|
||||
this.type = type.trim();
|
||||
this.name = name.trim();
|
||||
|
||||
hashCode = computeHashCode();
|
||||
}
|
||||
|
||||
public ResName(@NonNull String fullyQualifiedName) {
|
||||
Matcher matcher = FQN_PATTERN.matcher(fullyQualifiedName.trim());
|
||||
if (!matcher.find()) {
|
||||
throw new IllegalStateException("\"" + fullyQualifiedName + "\" is not fully qualified");
|
||||
}
|
||||
packageName = matcher.group(NAMESPACE);
|
||||
type = matcher.group(TYPE).trim();
|
||||
name = matcher.group(NAME).trim();
|
||||
|
||||
hashCode = computeHashCode();
|
||||
if (packageName.equals("xmlns")) throw new IllegalStateException("\"" + fullyQualifiedName + "\" unexpected");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null if the resource could not be qualified.
|
||||
*/
|
||||
public static String qualifyResourceName(@NonNull String possiblyQualifiedResourceName, String defaultPackageName, String defaultType) {
|
||||
ResName resName = qualifyResName(possiblyQualifiedResourceName, defaultPackageName, defaultType);
|
||||
return resName != null ? resName.getFullyQualifiedName() : null;
|
||||
}
|
||||
|
||||
public static ResName qualifyResName(@NonNull String possiblyQualifiedResourceName, ResName defaults) {
|
||||
return qualifyResName(possiblyQualifiedResourceName, defaults.packageName, defaults.type);
|
||||
}
|
||||
|
||||
public static ResName qualifyResName(@NonNull String possiblyQualifiedResourceName, String defaultPackageName, String defaultType) {
|
||||
int indexOfColon = possiblyQualifiedResourceName.indexOf(':');
|
||||
int indexOfSlash = possiblyQualifiedResourceName.indexOf('/');
|
||||
String type = null;
|
||||
String packageName = null;
|
||||
String name = possiblyQualifiedResourceName;
|
||||
if (indexOfColon > indexOfSlash) {
|
||||
if (indexOfSlash > 0) {
|
||||
type = possiblyQualifiedResourceName.substring(0, indexOfSlash);
|
||||
}
|
||||
packageName = possiblyQualifiedResourceName.substring(indexOfSlash + 1, indexOfColon);
|
||||
name = possiblyQualifiedResourceName.substring(indexOfColon + 1);
|
||||
} else if (indexOfSlash > indexOfColon) {
|
||||
if (indexOfColon > 0) {
|
||||
packageName = possiblyQualifiedResourceName.substring(0, indexOfColon);
|
||||
}
|
||||
type = possiblyQualifiedResourceName.substring(indexOfColon + 1, indexOfSlash);
|
||||
name = possiblyQualifiedResourceName.substring(indexOfSlash + 1);
|
||||
}
|
||||
|
||||
if ((type == null && defaultType == null) || (packageName == null && defaultPackageName == null)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (packageName == null) {
|
||||
packageName = defaultPackageName;
|
||||
} else if ("*android".equals(packageName)) {
|
||||
packageName = "android";
|
||||
}
|
||||
|
||||
return new ResName(packageName, type == null ? defaultType : type, name);
|
||||
}
|
||||
|
||||
public static String qualifyResName(String possiblyQualifiedResourceName, String contextPackageName) {
|
||||
if (possiblyQualifiedResourceName == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (AttributeResource.isNull(possiblyQualifiedResourceName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Was not able to fully qualify the resource name
|
||||
String fullyQualifiedResourceName = qualifyResourceName(possiblyQualifiedResourceName, contextPackageName, null);
|
||||
if (fullyQualifiedResourceName == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return fullyQualifiedResourceName.replaceAll("[@+]", "");
|
||||
}
|
||||
|
||||
public static ResName qualifyFromFilePath(@NonNull final String packageName, @NonNull final String filePath) {
|
||||
final File file = new File(filePath);
|
||||
final String type = file.getParentFile().getName().split("-", 0)[0];
|
||||
final String name = baseNameFor(file.getName());
|
||||
|
||||
return new ResName(packageName, type, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
ResName resName = (ResName) o;
|
||||
|
||||
if (hashCode() != resName.hashCode()) return false;
|
||||
|
||||
if (!packageName.equals(resName.packageName)) return false;
|
||||
if (!type.equals(resName.type)) return false;
|
||||
if (!name.equals(resName.name)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ResName{" + getFullyQualifiedName() + "}";
|
||||
}
|
||||
|
||||
public String getFullyQualifiedName() {
|
||||
return packageName + ":" + type + "/" + name;
|
||||
}
|
||||
|
||||
public String getNamespaceUri() {
|
||||
return "http://schemas.android.com/apk/res/" + packageName;
|
||||
}
|
||||
|
||||
public ResName withPackageName(String packageName) {
|
||||
if (packageName.equals(this.packageName)) return this;
|
||||
return new ResName(packageName, type, name);
|
||||
}
|
||||
|
||||
public void mustBe(String expectedType) {
|
||||
if (!type.equals(expectedType)) {
|
||||
throw new RuntimeException("expected " + getFullyQualifiedName() + " to be a " + expectedType + ", is a " + type);
|
||||
}
|
||||
}
|
||||
|
||||
private int computeHashCode() {
|
||||
int result = packageName.hashCode();
|
||||
result = 31 * result + type.hashCode();
|
||||
result = 31 * result + name.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
static String baseNameFor(String name) {
|
||||
int dotIndex = name.indexOf(".");
|
||||
return dotIndex >= 0 ? name.substring(0, dotIndex) : name;
|
||||
}
|
||||
}
|
||||
-80
@@ -1,80 +0,0 @@
|
||||
/************************************************************************************
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
*
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**************************************************************************************/
|
||||
package com.itsaky.androidide.ui.resources;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class ResourceIdGenerator {
|
||||
|
||||
private final Map<String, TypeTracker> typeInfo = new HashMap<>();
|
||||
private int packageIdentifier;
|
||||
|
||||
private static class TypeTracker {
|
||||
private int typeIdentifier;
|
||||
private int currentMaxEntry;
|
||||
|
||||
TypeTracker(int typeIdentifier) {
|
||||
this.typeIdentifier = typeIdentifier;
|
||||
}
|
||||
|
||||
void record(int entryIdentifier) {
|
||||
currentMaxEntry = Math.max(currentMaxEntry, entryIdentifier);
|
||||
}
|
||||
|
||||
public int getFreeIdentifier() {
|
||||
return ++currentMaxEntry;
|
||||
}
|
||||
|
||||
public int getTypeIdentifier() {
|
||||
return typeIdentifier;
|
||||
}
|
||||
}
|
||||
|
||||
ResourceIdGenerator(int packageIdentifier) {
|
||||
this.packageIdentifier = packageIdentifier;
|
||||
}
|
||||
|
||||
public void record(int resId, String type, String name) {
|
||||
TypeTracker typeTracker = typeInfo.get(type);
|
||||
if (typeTracker == null) {
|
||||
typeTracker = new TypeTracker(ResourceIds.getTypeIdentifier(resId));
|
||||
typeInfo.put(type, typeTracker);
|
||||
}
|
||||
typeTracker.record(ResourceIds.getEntryIdentifier(resId));
|
||||
}
|
||||
|
||||
public int generate(String type, String name) {
|
||||
TypeTracker typeTracker = typeInfo.get(type);
|
||||
if (typeTracker == null) {
|
||||
typeTracker = new TypeTracker(getNextFreeTypeIdentifier());
|
||||
typeInfo.put(type, typeTracker);
|
||||
}
|
||||
return ResourceIds.makeIdentifer(packageIdentifier, typeTracker.getTypeIdentifier(), typeTracker.getFreeIdentifier());
|
||||
}
|
||||
|
||||
private int getNextFreeTypeIdentifier() {
|
||||
int result = 0;
|
||||
for (TypeTracker typeTracker : typeInfo.values()) {
|
||||
result = Math.max(result, typeTracker.getTypeIdentifier());
|
||||
}
|
||||
return ++result;
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
/************************************************************************************
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
*
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**************************************************************************************/
|
||||
package com.itsaky.androidide.ui.resources;
|
||||
|
||||
public class ResourceIds {
|
||||
public static boolean isFrameworkResource(int resId) {
|
||||
return ((resId >>> 24) == 0x1);
|
||||
}
|
||||
|
||||
public static int getPackageIdentifier(int resId) {
|
||||
return (resId >>> 24);
|
||||
}
|
||||
|
||||
public static int getTypeIdentifier(int resId) {
|
||||
return (resId & 0x00FF0000) >>> 16;
|
||||
}
|
||||
|
||||
public static int getEntryIdentifier(int resId) {
|
||||
return resId & 0x0000FFFF;
|
||||
}
|
||||
|
||||
public static int makeIdentifer(int packageIdentifier, int typeIdentifier, int entryIdenifier) {
|
||||
return packageIdentifier << 24 | typeIdentifier << 16 | entryIdenifier;
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
/************************************************************************************
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
*
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**************************************************************************************/
|
||||
package com.itsaky.androidide.ui.resources;
|
||||
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.HashBiMap;
|
||||
|
||||
public class ResourceTable {
|
||||
|
||||
private int packageIdentifier = 0;
|
||||
private final String packageName;
|
||||
private final BiMap<Integer, ResName> resourceTable = HashBiMap.create();
|
||||
|
||||
private final ResourceIdGenerator androidResourceIdGenerator = new ResourceIdGenerator(0x01);
|
||||
|
||||
public ResourceTable(String packageName) {
|
||||
this.packageName = packageName;
|
||||
}
|
||||
|
||||
public Integer getResourceId(ResName resName) {
|
||||
Integer id = resourceTable.inverse().get(resName);
|
||||
if (id == null && resName != null && resName.name.contains(".")) {
|
||||
id = resourceTable.inverse().get(new ResName(resName.packageName, resName.type, underscorize(resName.name)));
|
||||
}
|
||||
return id != null ? id : 0;
|
||||
}
|
||||
|
||||
public int getPackageIdentifier() {
|
||||
return packageIdentifier;
|
||||
}
|
||||
|
||||
void addResource(int resId, String type, String name) {
|
||||
if (ResourceIds.isFrameworkResource(resId)) {
|
||||
androidResourceIdGenerator.record(resId, type, name);
|
||||
}
|
||||
ResName resName = new ResName(packageName, type, name);
|
||||
int resIdPackageIdentifier = ResourceIds.getPackageIdentifier(resId);
|
||||
if (getPackageIdentifier() == 0) {
|
||||
this.packageIdentifier = resIdPackageIdentifier;
|
||||
} else if (getPackageIdentifier() != resIdPackageIdentifier) {
|
||||
throw new IllegalArgumentException("Incompatible package for " + packageName + ":" + type + "/" + name + " with resId " + resIdPackageIdentifier + " to ResourceIndex with packageIdentifier " + getPackageIdentifier());
|
||||
}
|
||||
|
||||
ResName existingEntry = resourceTable.put(resId, resName);
|
||||
if (existingEntry != null && !existingEntry.equals(resName)) {
|
||||
throw new IllegalArgumentException("ResId " + Integer.toHexString(resId) + " mapped to both " + resName + " and " + existingEntry);
|
||||
}
|
||||
}
|
||||
|
||||
private static String underscorize(String s) {
|
||||
return s == null ? null : s.replace('.', '_');
|
||||
}
|
||||
}
|
||||
-123
@@ -1,123 +0,0 @@
|
||||
/************************************************************************************
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
*
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**************************************************************************************/
|
||||
package com.itsaky.androidide.ui.resources;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ResourceTableFactory {
|
||||
|
||||
@Nullable
|
||||
public static ResourceTable newFrameworkResourceTable () {
|
||||
final ResourceTable table = new ResourceTable ("android");
|
||||
final Class<?> androidR = android.R.class;
|
||||
try {
|
||||
processResources(table, androidR);
|
||||
} catch (IllegalArgumentException|IllegalAccessException e) {
|
||||
return null;
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
private static void processResources(ResourceTable table, Class<?> rClass) throws IllegalArgumentException, IllegalAccessException {
|
||||
final Map<String, List<Integer>> styleableMap = new HashMap<>();
|
||||
for (Class<?> innerClass : rClass.getClasses()) {
|
||||
if ("styleable".equals(innerClass.getSimpleName())) {
|
||||
for (final Field attr : innerClass.getDeclaredFields()) {
|
||||
final Class<?> attrClassType = attr.getType();
|
||||
if (attrClassType == int[].class) { // <declare-styleable> declaration
|
||||
addStyleableGroup (styleableMap, attr);
|
||||
} else if (attrClassType == int.class) { // Member of <declare-styleable>
|
||||
addStyleableMember (table, styleableMap, attr);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (Field field : innerClass.getDeclaredFields()) {
|
||||
if (field.getType().equals(Integer.TYPE) && Modifier.isStatic(field.getModifiers())) {
|
||||
int id = field.getInt(null);
|
||||
String resourceName = field.getName();
|
||||
if (id != 0) {
|
||||
table.addResource(id, innerClass.getSimpleName(), resourceName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void addStyleableGroup(final Map<String, List<Integer>> styleableMap, final Field attr) throws IllegalArgumentException, IllegalAccessException {
|
||||
final String name = attr.getName();
|
||||
List<Integer> members = styleableMap.get(name);
|
||||
if (members == null) {
|
||||
members = new ArrayList<>();
|
||||
}
|
||||
final int[] mm = (int[]) attr.get(null);
|
||||
if (mm == null || mm.length <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i=0;i<mm.length;i++) {
|
||||
members.add(mm[i]);
|
||||
}
|
||||
|
||||
styleableMap.put(name, members);
|
||||
}
|
||||
|
||||
private static void addStyleableMember(final ResourceTable table, final Map<String, List<Integer>> styleableMap, final Field attr) throws IllegalArgumentException, IllegalAccessException {
|
||||
final String name = attr.getName();
|
||||
final int separator = findGroupAndAttrNameSeparator (styleableMap, name); // If this is a <declare-styleable> member, then the name will definitely contain am underscore
|
||||
final String groupName = name.substring(0, separator);
|
||||
final String attrName = name.substring(separator + 1);
|
||||
|
||||
final List<Integer> members = styleableMap.get(groupName);
|
||||
if (members == null) {
|
||||
throw new IllegalStateException ("No styleable declared for " + groupName + "\nstyleableMap = " + styleableMap); // No entry for this name
|
||||
}
|
||||
|
||||
final int index = (int) attr.get(null);
|
||||
if (index < 0 || index >= members.size()) {
|
||||
throw new IndexOutOfBoundsException ("Index " + index + " is out of bounds (size=" + members.size() + "). name=" + name + ", grpName=" + groupName + ", attrName=" + attrName);
|
||||
}
|
||||
|
||||
table.addResource(members.get(index), "attr", attrName);
|
||||
}
|
||||
|
||||
private static int findGroupAndAttrNameSeparator(Map<String, List<Integer>> styleableMap, String name) {
|
||||
int index = name.length() - 1;
|
||||
|
||||
while (index > 0) {
|
||||
int i = name.lastIndexOf("_", index);
|
||||
String group = name.substring(0, i);
|
||||
List<Integer> mm = styleableMap.get(group);
|
||||
if (mm != null) {
|
||||
return i;
|
||||
} else {
|
||||
index = i - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
/************************************************************************************
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
*
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/************************************************************************************
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
+48
-35
@@ -1,7 +1,5 @@
|
||||
/************************************************************************************
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
*
|
||||
* This file is part of AndroidIDE
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -36,6 +34,7 @@ import androidx.core.view.GravityCompat;
|
||||
import com.itsaky.androidide.ui.inflater.IResourceFinder;
|
||||
import com.itsaky.androidide.ui.view.IAttribute;
|
||||
import com.itsaky.androidide.ui.view.IAttributeAdapter;
|
||||
import com.itsaky.androidide.utils.Logger;
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -47,34 +46,40 @@ public class BaseViewAttrAdapter implements IAttributeAdapter {
|
||||
|
||||
private final Pattern HEX_COLOR = Pattern.compile("#[a-fA-F0-9]{6,8}");
|
||||
|
||||
protected static final Logger LOG = Logger.instance ("BaseViewAttrAdapter");
|
||||
public static final int ENUM_NOT_FOUND = -4116;
|
||||
|
||||
@Override
|
||||
public boolean isApplicableTo(View view) {
|
||||
return true;
|
||||
return true; // Can be applied to any view
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(IAttribute attribute, View view, IResourceFinder resFinder) {
|
||||
final String namespace = attribute.getNamespace();
|
||||
final String name = attribute.getNamespace();
|
||||
final String name = attribute.getAttributeName();
|
||||
final String value = attribute.getValue();
|
||||
final ViewGroup.LayoutParams params = view.getLayoutParams();
|
||||
final Resources res = view.getResources();
|
||||
final DisplayMetrics dm = res.getDisplayMetrics();
|
||||
final Context ctx = view.getContext();
|
||||
|
||||
if (canHandleNamespace(namespace)) {
|
||||
if (!canHandleNamespace(namespace)) {
|
||||
LOG.error("Cannot handle namespace: " + namespace);
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG.debug ("Adding attribute", attribute);
|
||||
|
||||
boolean handled = true;
|
||||
switch (name) {
|
||||
case "layout_height" :
|
||||
params.height = parseDimension (value, -2, dm, resFinder);
|
||||
LOG.error("Added layout_height", params.height);
|
||||
break;
|
||||
case "layout_width" :
|
||||
params.width = parseDimension (value, -2, dm, resFinder);
|
||||
LOG.error("Added layout_width", params.width);
|
||||
break;
|
||||
case "alpha" :
|
||||
view.setAlpha(parseFloat(value));
|
||||
@@ -221,33 +226,12 @@ public class BaseViewAttrAdapter implements IAttributeAdapter {
|
||||
break;
|
||||
}
|
||||
|
||||
// In case these attributes are related to margins
|
||||
// We need to apply them by casting the params to ViewGroup.MarginLayoutParams
|
||||
if (!handled && params instanceof ViewGroup.MarginLayoutParams) {
|
||||
ViewGroup.MarginLayoutParams marginParams = (ViewGroup.MarginLayoutParams) params;
|
||||
switch (name) {
|
||||
case "layout_margin" :
|
||||
final int margin = parseDimension(value, 0, dm, resFinder);
|
||||
marginParams.setMargins(margin, margin, margin, margin);
|
||||
break;
|
||||
case "layout_marginLeft" :
|
||||
marginParams.leftMargin = parseDimension(value, 0, dm, resFinder);
|
||||
break;
|
||||
case "layout_marginTop" :
|
||||
marginParams.topMargin = parseDimension(value, 0, dm, resFinder);
|
||||
break;
|
||||
case "layout_marginRight" :
|
||||
marginParams.rightMargin = parseDimension(value, 0, dm, resFinder);
|
||||
break;
|
||||
case "layout_marginBottom" :
|
||||
marginParams.bottomMargin = parseDimension(value, 0, dm, resFinder);
|
||||
break;
|
||||
case "layout_marginStart" :
|
||||
marginParams.setMarginStart(parseDimension(value, 0, dm, resFinder));
|
||||
break;
|
||||
case "layout_marginEnd" :
|
||||
marginParams.setMarginEnd(parseDimension(value, 0, dm, resFinder));
|
||||
break;
|
||||
// ----- Handle attributes related to parent ------
|
||||
if (!handled) {
|
||||
|
||||
// Layout Margins
|
||||
if (params instanceof ViewGroup.MarginLayoutParams) {
|
||||
handleMarginParams((ViewGroup.MarginLayoutParams) params, name, value, dm, resFinder);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,6 +239,33 @@ public class BaseViewAttrAdapter implements IAttributeAdapter {
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
private void handleMarginParams(ViewGroup.MarginLayoutParams params, String name, String value, DisplayMetrics dm, IResourceFinder resFinder) {
|
||||
switch (name) {
|
||||
case "layout_margin" :
|
||||
final int margin = parseDimension(value, 0, dm, resFinder);
|
||||
params.setMargins(margin, margin, margin, margin);
|
||||
break;
|
||||
case "layout_marginLeft" :
|
||||
params.leftMargin = parseDimension(value, 0, dm, resFinder);
|
||||
break;
|
||||
case "layout_marginTop" :
|
||||
params.topMargin = parseDimension(value, 0, dm, resFinder);
|
||||
break;
|
||||
case "layout_marginRight" :
|
||||
params.rightMargin = parseDimension(value, 0, dm, resFinder);
|
||||
break;
|
||||
case "layout_marginBottom" :
|
||||
params.bottomMargin = parseDimension(value, 0, dm, resFinder);
|
||||
break;
|
||||
case "layout_marginStart" :
|
||||
params.setMarginStart(parseDimension(value, 0, dm, resFinder));
|
||||
break;
|
||||
case "layout_marginEnd" :
|
||||
params.setMarginEnd(parseDimension(value, 0, dm, resFinder));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean canHandleNamespace(String namespace) {
|
||||
// TODO Compare namespace URI instead of name
|
||||
@@ -428,7 +439,7 @@ public class BaseViewAttrAdapter implements IAttributeAdapter {
|
||||
case "drawable" :
|
||||
return ContextCompat.getDrawable(ctx, id);
|
||||
default :
|
||||
return newTransparentDrawable();
|
||||
return newTransparentDrawable();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -462,7 +473,9 @@ public class BaseViewAttrAdapter implements IAttributeAdapter {
|
||||
if (HEX_COLOR.matcher(color).matches()) {
|
||||
try {
|
||||
return Color.parseColor(color);
|
||||
} catch (Throwable th) {}
|
||||
} catch (Throwable th) {
|
||||
// Ignored
|
||||
}
|
||||
} else if (color.startsWith("@color/")) {
|
||||
return parseColor(resFinder.findColor(color.substring("@color/".length())), resFinder, ctx);
|
||||
} else if (color.startsWith("@android:color/")) {
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@ public class BaseViewGroupAttrAdapter extends BaseViewAttrAdapter {
|
||||
}
|
||||
final ViewGroup group = (ViewGroup) view;
|
||||
final String namespace = attribute.getNamespace();
|
||||
final String name = attribute.getNamespace();
|
||||
final String name = attribute.getAttributeName();
|
||||
final String value = attribute.getValue();
|
||||
|
||||
if (!canHandleNamespace(namespace)) {
|
||||
|
||||
+1
-3
@@ -1,8 +1,6 @@
|
||||
/************************************************************************************
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
+1
-3
@@ -1,8 +1,6 @@
|
||||
/************************************************************************************
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
*
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
@@ -43,7 +41,7 @@ public class LinearLayoutAttrAdapter extends BaseViewGroupAttrAdapter {
|
||||
|
||||
final LinearLayout linear = (LinearLayout) view;
|
||||
final String namespace = attribute.getNamespace();
|
||||
final String name = attribute.getNamespace();
|
||||
final String name = attribute.getAttributeName();
|
||||
final String value = attribute.getValue();
|
||||
|
||||
if (!canHandleNamespace(namespace)) {
|
||||
|
||||
+3
-5
@@ -1,8 +1,6 @@
|
||||
/************************************************************************************
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
@@ -50,7 +48,7 @@ public class TextViewAttrAdapter extends BaseViewAttrAdapter {
|
||||
|
||||
final TextView text = (TextView) view;
|
||||
final String namespace = attribute.getNamespace();
|
||||
final String name = attribute.getNamespace();
|
||||
final String name = attribute.getAttributeName();
|
||||
final String value = attribute.getValue();
|
||||
final ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
|
||||
final Resources res = view.getResources();
|
||||
@@ -59,7 +57,7 @@ public class TextViewAttrAdapter extends BaseViewAttrAdapter {
|
||||
final Drawable[] drawables = text.getCompoundDrawables();
|
||||
final Drawable[] drawablesRelative = text.getCompoundDrawablesRelative();
|
||||
|
||||
if (canHandleNamespace(namespace)) {
|
||||
if (!canHandleNamespace(namespace)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/************************************************************************************
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
*
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
@@ -29,10 +27,11 @@ import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.Objects;
|
||||
|
||||
public abstract class BaseView implements IView {
|
||||
|
||||
protected final List<IAttribute> attributes = new ArrayList<>();
|
||||
protected final Set<IAttribute> attributes = new HashSet<>();
|
||||
protected final Set<IAttributeAdapter> attrAdapters = new HashSet<>();
|
||||
|
||||
protected final String qualifiedName;
|
||||
@@ -83,14 +82,13 @@ public abstract class BaseView implements IView {
|
||||
this.attributes.add(attr);
|
||||
|
||||
for (IAttributeAdapter adapter : attrAdapters) {
|
||||
if (adapter.isApplicableTo(asView())) {
|
||||
if (adapter.apply(attr, asView(), resFinder)) {
|
||||
if (adapter.isApplicableTo(asView())
|
||||
&& adapter.apply(attr, asView(), resFinder)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void removeAttribute(IAttribute attr) {
|
||||
this.attributes.remove(attr);
|
||||
@@ -121,16 +119,18 @@ public abstract class BaseView implements IView {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (obj instanceof IView) {
|
||||
IView that = (IView) obj;
|
||||
return this.asView().equals(that.asView());
|
||||
}
|
||||
|
||||
return false;
|
||||
return this.hashCode() == obj.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return asView().hashCode();
|
||||
return Objects.hash(
|
||||
attributes,
|
||||
attrAdapters,
|
||||
qualifiedName,
|
||||
view,
|
||||
parent,
|
||||
isPlaceholder
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/************************************************************************************
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/************************************************************************************
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
@@ -24,6 +22,7 @@ import com.itsaky.androidide.ui.view.IAttribute;
|
||||
import com.itsaky.androidide.ui.view.IFixedValue;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.Objects;
|
||||
|
||||
public class UiAttribute implements IAttribute {
|
||||
|
||||
@@ -76,18 +75,14 @@ public class UiAttribute implements IAttribute {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof UiAttribute) {
|
||||
UiAttribute that = (UiAttribute) obj;
|
||||
return this.getNamespace().equals(that.getNamespace())
|
||||
&& this.getAttributeName().equals(that.getAttributeName())
|
||||
&& this.getValue().equals(that.getValue())
|
||||
&& this.getFixedValues().equals(that.getFixedValues());
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
return this.hashCode() == obj.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return toString().hashCode();
|
||||
return Objects.hash(namespace, name, value, fixedValues);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/************************************************************************************
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/************************************************************************************
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
*
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
Reference in New Issue
Block a user